//===--- PCHWriterDecl.cpp - Declaration Serialization --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements serialization for Declarations. // //===----------------------------------------------------------------------===// #include "clang/Frontend/PCHWriter.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; //===----------------------------------------------------------------------===// // Declaration serialization //===----------------------------------------------------------------------===// namespace clang { class PCHDeclWriter : public DeclVisitor { PCHWriter &Writer; ASTContext &Context; PCHWriter::RecordData &Record; public: pch::DeclCode Code; unsigned AbbrevToUse; PCHDeclWriter(PCHWriter &Writer, ASTContext &Context, PCHWriter::RecordData &Record) : Writer(Writer), Context(Context), Record(Record) { } void Visit(Decl *D); void VisitDecl(Decl *D); void VisitTranslationUnitDecl(TranslationUnitDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitTypeDecl(TypeDecl *D); void VisitTypedefDecl(TypedefDecl *D); void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); void VisitTagDecl(TagDecl *D); void VisitEnumDecl(EnumDecl *D); void VisitRecordDecl(RecordDecl *D); void VisitCXXRecordDecl(CXXRecordDecl *D); void VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *D); void VisitFunctionDecl(FunctionDecl *D); void VisitCXXMethodDecl(CXXMethodDecl *D); void VisitCXXConstructorDecl(CXXConstructorDecl *D); void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitBlockDecl(BlockDecl *D); void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, uint64_t VisibleOffset); template void VisitRedeclarable(Redeclarable *D); // FIXME: Put in the same order is DeclNodes.td? void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCContainerDecl(ObjCContainerDecl *D); void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); void VisitObjCIvarDecl(ObjCIvarDecl *D); void VisitObjCProtocolDecl(ObjCProtocolDecl *D); void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); void VisitObjCClassDecl(ObjCClassDecl *D); void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); void VisitObjCCategoryDecl(ObjCCategoryDecl *D); void VisitObjCImplDecl(ObjCImplDecl *D); void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); void VisitObjCImplementationDecl(ObjCImplementationDecl *D); void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); }; } void PCHDeclWriter::Visit(Decl *D) { DeclVisitor::Visit(D); // Handle FunctionDecl's body here and write it after all other Stmts/Exprs // have been written. We want it last because we will not read it back when // retrieving it from the PCH, we'll just lazily set the offset. if (FunctionDecl *FD = dyn_cast(D)) { Record.push_back(FD->isThisDeclarationADefinition()); if (FD->isThisDeclarationADefinition()) Writer.AddStmt(FD->getBody()); } } void PCHDeclWriter::VisitDecl(Decl *D) { Writer.AddDeclRef(cast_or_null(D->getDeclContext()), Record); Writer.AddDeclRef(cast_or_null(D->getLexicalDeclContext()), Record); Writer.AddSourceLocation(D->getLocation(), Record); Record.push_back(D->isInvalidDecl()); Record.push_back(D->hasAttrs()); Record.push_back(D->isImplicit()); Record.push_back(D->isUsed(false)); Record.push_back(D->getAccess()); Record.push_back(D->getPCHLevel()); } void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { VisitDecl(D); Writer.AddDeclRef(D->getAnonymousNamespace(), Record); Code = pch::DECL_TRANSLATION_UNIT; } void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) { VisitDecl(D); Writer.AddDeclarationName(D->getDeclName(), Record); } void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { VisitNamedDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); } void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { VisitTypeDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); Code = pch::DECL_TYPEDEF; } void PCHDeclWriter::VisitTagDecl(TagDecl *D) { VisitTypeDecl(D); Record.push_back(D->getIdentifierNamespace()); VisitRedeclarable(D); Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding Record.push_back(D->isDefinition()); Record.push_back(D->isEmbeddedInDeclarator()); Writer.AddSourceLocation(D->getRBraceLoc(), Record); Writer.AddSourceLocation(D->getTagKeywordLoc(), Record); // FIXME: maybe write optional qualifier and its range. Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); } void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { VisitTagDecl(D); Writer.AddTypeRef(D->getIntegerType(), Record); Writer.AddTypeRef(D->getPromotionType(), Record); Record.push_back(D->getNumPositiveBits()); Record.push_back(D->getNumNegativeBits()); Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record); Code = pch::DECL_ENUM; } void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) { VisitTagDecl(D); Record.push_back(D->hasFlexibleArrayMember()); Record.push_back(D->isAnonymousStructOrUnion()); Record.push_back(D->hasObjectMember()); Code = pch::DECL_RECORD; } void PCHDeclWriter::VisitValueDecl(ValueDecl *D) { VisitNamedDecl(D); Writer.AddTypeRef(D->getType(), Record); } void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { VisitValueDecl(D); Record.push_back(D->getInitExpr()? 1 : 0); if (D->getInitExpr()) Writer.AddStmt(D->getInitExpr()); Writer.AddAPSInt(D->getInitVal(), Record); Code = pch::DECL_ENUM_CONSTANT; } void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); // FIXME: write optional qualifier and its range. } void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { VisitDeclaratorDecl(D); // FIXME: write DeclarationNameLoc. Record.push_back(D->getIdentifierNamespace()); Record.push_back(D->getTemplatedKind()); switch (D->getTemplatedKind()) { default: assert(false && "Unhandled TemplatedKind!"); break; case FunctionDecl::TK_NonTemplate: break; case FunctionDecl::TK_FunctionTemplate: Writer.AddDeclRef(D->getDescribedFunctionTemplate(), Record); break; case FunctionDecl::TK_MemberSpecialization: { MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo(); Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record); Record.push_back(MemberInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record); break; } case FunctionDecl::TK_FunctionTemplateSpecialization: { FunctionTemplateSpecializationInfo * FTSInfo = D->getTemplateSpecializationInfo(); // We want it canonical to guarantee that it has a Common*. Writer.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl(), Record); Record.push_back(FTSInfo->getTemplateSpecializationKind()); // Template arguments. Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record); // Template args as written. Record.push_back(FTSInfo->TemplateArgumentsAsWritten != 0); if (FTSInfo->TemplateArgumentsAsWritten) { Record.push_back(FTSInfo->TemplateArgumentsAsWritten->size()); for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->size(); i!=e; ++i) Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i], Record); Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getLAngleLoc(), Record); Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getRAngleLoc(), Record); } Writer.AddSourceLocation(FTSInfo->getPointOfInstantiation(), Record); break; } case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { DependentFunctionTemplateSpecializationInfo * DFTSInfo = D->getDependentSpecializationInfo(); // Templates. Record.push_back(DFTSInfo->getNumTemplates()); for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i) Writer.AddDeclRef(DFTSInfo->getTemplate(i), Record); // Templates args. Record.push_back(DFTSInfo->getNumTemplateArgs()); for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i) Writer.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i), Record); Writer.AddSourceLocation(DFTSInfo->getLAngleLoc(), Record); Writer.AddSourceLocation(DFTSInfo->getRAngleLoc(), Record); break; } } // FunctionDecl's body is handled last at PCHWriterDecl::Visit, // after everything else is written. VisitRedeclarable(D); Record.push_back(D->getStorageClass()); // FIXME: stable encoding Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->isInlineSpecified()); Record.push_back(D->isVirtualAsWritten()); Record.push_back(D->isPure()); Record.push_back(D->hasInheritedPrototype()); Record.push_back(D->hasWrittenPrototype()); Record.push_back(D->isDeleted()); Record.push_back(D->isTrivial()); Record.push_back(D->isCopyAssignment()); Record.push_back(D->hasImplicitReturnZero()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); Code = pch::DECL_FUNCTION; } void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { VisitNamedDecl(D); // FIXME: convert to LazyStmtPtr? // Unlike C/C++, method bodies will never be in header files. bool HasBodyStuff = D->getBody() != 0 || D->getSelfDecl() != 0 || D->getCmdDecl() != 0; Record.push_back(HasBodyStuff); if (HasBodyStuff) { Writer.AddStmt(D->getBody()); Writer.AddDeclRef(D->getSelfDecl(), Record); Writer.AddDeclRef(D->getCmdDecl(), Record); } Record.push_back(D->isInstanceMethod()); Record.push_back(D->isVariadic()); Record.push_back(D->isSynthesized()); Record.push_back(D->isDefined()); // FIXME: stable encoding for @required/@optional Record.push_back(D->getImplementationControl()); // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway Record.push_back(D->getObjCDeclQualifier()); Record.push_back(D->getNumSelectorArgs()); Writer.AddTypeRef(D->getResultType(), Record); Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->param_size()); for (ObjCMethodDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); Code = pch::DECL_OBJC_METHOD; } void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { VisitNamedDecl(D); Writer.AddSourceRange(D->getAtEndRange(), Record); // Abstract class (no need to define a stable pch::DECL code). } void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { VisitObjCContainerDecl(D); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); Writer.AddDeclRef(D->getSuperClass(), Record); Record.push_back(D->protocol_size()); for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(), PEnd = D->protocol_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); PL != PLEnd; ++PL) Writer.AddSourceLocation(*PL, Record); Record.push_back(D->ivar_size()); for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(), IEnd = D->ivar_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); Writer.AddDeclRef(D->getCategoryList(), Record); Record.push_back(D->isForwardDecl()); Record.push_back(D->isImplicitInterfaceDecl()); Writer.AddSourceLocation(D->getClassLoc(), Record); Writer.AddSourceLocation(D->getSuperClassLoc(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record); Code = pch::DECL_OBJC_INTERFACE; } void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { VisitFieldDecl(D); // FIXME: stable encoding for @public/@private/@protected/@package Record.push_back(D->getAccessControl()); Record.push_back(D->getSynthesize()); Code = pch::DECL_OBJC_IVAR; } void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { VisitObjCContainerDecl(D); Record.push_back(D->isForwardDecl()); Writer.AddSourceLocation(D->getLocEnd(), Record); Record.push_back(D->protocol_size()); for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); PL != PLEnd; ++PL) Writer.AddSourceLocation(*PL, Record); Code = pch::DECL_OBJC_PROTOCOL; } void PCHDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { VisitFieldDecl(D); Code = pch::DECL_OBJC_AT_DEFS_FIELD; } void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { VisitDecl(D); Record.push_back(D->size()); for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) Writer.AddDeclRef(I->getInterface(), Record); for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) Writer.AddSourceLocation(I->getLocation(), Record); Code = pch::DECL_OBJC_CLASS; } void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { VisitDecl(D); Record.push_back(D->protocol_size()); for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); for (ObjCForwardProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); PL != PLEnd; ++PL) Writer.AddSourceLocation(*PL, Record); Code = pch::DECL_OBJC_FORWARD_PROTOCOL; } void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { VisitObjCContainerDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); Record.push_back(D->protocol_size()); for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); for (ObjCCategoryDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); PL != PLEnd; ++PL) Writer.AddSourceLocation(*PL, Record); Writer.AddDeclRef(D->getNextClassCategory(), Record); Writer.AddSourceLocation(D->getAtLoc(), Record); Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); Code = pch::DECL_OBJC_CATEGORY; } void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { VisitNamedDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); Code = pch::DECL_OBJC_COMPATIBLE_ALIAS; } void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAtLoc(), Record); Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyAttributes()); Record.push_back((unsigned)D->getPropertyAttributesAsWritten()); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyImplementation()); Writer.AddDeclarationName(D->getGetterName(), Record); Writer.AddDeclarationName(D->getSetterName(), Record); Writer.AddDeclRef(D->getGetterMethodDecl(), Record); Writer.AddDeclRef(D->getSetterMethodDecl(), Record); Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); Code = pch::DECL_OBJC_PROPERTY; } void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) { VisitObjCContainerDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); // Abstract class (no need to define a stable pch::DECL code). } void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); Writer.AddIdentifierRef(D->getIdentifier(), Record); Code = pch::DECL_OBJC_CATEGORY_IMPL; } void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); Writer.AddDeclRef(D->getSuperClass(), Record); Writer.AddCXXBaseOrMemberInitializers(D->IvarInitializers, D->NumIvarInitializers, Record); Code = pch::DECL_OBJC_IMPLEMENTATION; } void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { VisitDecl(D); Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddDeclRef(D->getPropertyDecl(), Record); Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); Writer.AddStmt(D->getGetterCXXConstructor()); Writer.AddStmt(D->getSetterCXXAssignment()); Code = pch::DECL_OBJC_PROPERTY_IMPL; } void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); Record.push_back(D->getBitWidth()? 1 : 0); if (D->getBitWidth()) Writer.AddStmt(D->getBitWidth()); if (!D->getDeclName()) Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); Code = pch::DECL_FIELD; } void PCHDeclWriter::VisitVarDecl(VarDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->getStorageClass()); // FIXME: stable encoding Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->isThreadSpecified()); Record.push_back(D->hasCXXDirectInitializer()); Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); VisitRedeclarable(D); Record.push_back(D->getInit() ? 1 : 0); if (D->getInit()) Writer.AddStmt(D->getInit()); MemberSpecializationInfo *SpecInfo = D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0; Record.push_back(SpecInfo != 0); if (SpecInfo) { Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record); Record.push_back(SpecInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record); } Code = pch::DECL_VAR; } void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { VisitVarDecl(D); Code = pch::DECL_IMPLICIT_PARAM; } void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding Record.push_back(D->hasInheritedDefaultArg()); Record.push_back(D->hasUninstantiatedDefaultArg()); if (D->hasUninstantiatedDefaultArg()) Writer.AddStmt(D->getUninstantiatedDefaultArg()); Code = pch::DECL_PARM_VAR; // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here // we dynamically check for the properties that we optimize for, but don't // know are true of all PARM_VAR_DECLs. if (!D->getTypeSourceInfo() && !D->hasAttrs() && !D->isImplicit() && !D->isUsed(false) && D->getAccess() == AS_none && D->getPCHLevel() == 0 && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? D->getObjCDeclQualifier() == 0 && !D->hasInheritedDefaultArg() && D->getInit() == 0 && !D->hasUninstantiatedDefaultArg()) // No default expr. AbbrevToUse = Writer.getParmVarDeclAbbrev(); // Check things we know are true of *every* PARM_VAR_DECL, which is more than // just us assuming it. assert(!D->isInvalidDecl() && "Shouldn't emit invalid decls"); assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread"); assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl"); assert(!D->isStaticDataMember() && "PARM_VAR_DECL can't be static data member"); } void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAsmString()); Code = pch::DECL_FILE_SCOPE_ASM; } void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) { VisitDecl(D); Writer.AddStmt(D->getBody()); Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record); Record.push_back(D->param_size()); for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); Code = pch::DECL_BLOCK; } void PCHDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); // FIXME: It might be nice to serialize the brace locations for this // declaration, which don't seem to be readily available in the AST. Record.push_back(D->getLanguage()); Record.push_back(D->hasBraces()); Code = pch::DECL_LINKAGE_SPEC; } void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getLBracLoc(), Record); Writer.AddSourceLocation(D->getRBracLoc(), Record); Writer.AddDeclRef(D->getNextNamespace(), Record); // Only write one reference--original or anonymous Record.push_back(D->isOriginalNamespace()); if (D->isOriginalNamespace()) Writer.AddDeclRef(D->getAnonymousNamespace(), Record); else Writer.AddDeclRef(D->getOriginalNamespace(), Record); Code = pch::DECL_NAMESPACE; if (Writer.hasChain() && !D->isOriginalNamespace() && D->getOriginalNamespace()->getPCHLevel() > 0) { Writer.AddUpdatedNamespace(D->getOriginalNamespace()); } } void PCHDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getAliasLoc(), Record); Writer.AddSourceRange(D->getQualifierRange(), Record); Writer.AddNestedNameSpecifier(D->getQualifier(), Record); Writer.AddSourceLocation(D->getTargetNameLoc(), Record); Writer.AddDeclRef(D->getNamespace(), Record); Code = pch::DECL_NAMESPACE_ALIAS; } void PCHDeclWriter::VisitUsingDecl(UsingDecl *D) { VisitNamedDecl(D); Writer.AddSourceRange(D->getNestedNameRange(), Record); Writer.AddSourceLocation(D->getUsingLocation(), Record); Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record); Record.push_back(D->getNumShadowDecls()); for (UsingDecl::shadow_iterator P = D->shadow_begin(), PEnd = D->shadow_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); Record.push_back(D->isTypeName()); Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record); Code = pch::DECL_USING; } void PCHDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { VisitNamedDecl(D); Writer.AddDeclRef(D->getTargetDecl(), Record); Writer.AddDeclRef(D->getUsingDecl(), Record); Writer.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D), Record); Code = pch::DECL_USING_SHADOW; } void PCHDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { VisitNamedDecl(D); Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record); Writer.AddSourceRange(D->getQualifierRange(), Record); Writer.AddNestedNameSpecifier(D->getQualifier(), Record); Writer.AddSourceLocation(D->getIdentLocation(), Record); Writer.AddDeclRef(D->getNominatedNamespace(), Record); Writer.AddDeclRef(dyn_cast(D->getCommonAncestor()), Record); Code = pch::DECL_USING_DIRECTIVE; } void PCHDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { VisitValueDecl(D); Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); Writer.AddSourceLocation(D->getUsingLoc(), Record); Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); Code = pch::DECL_UNRESOLVED_USING_VALUE; } void PCHDeclWriter::VisitUnresolvedUsingTypenameDecl( UnresolvedUsingTypenameDecl *D) { VisitTypeDecl(D); Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); Writer.AddSourceLocation(D->getUsingLoc(), Record); Writer.AddSourceLocation(D->getTypenameLoc(), Record); Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); Code = pch::DECL_UNRESOLVED_USING_TYPENAME; } void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { // See comments at PCHDeclReader::VisitCXXRecordDecl about why this happens // before VisitRecordDecl. enum { Data_NoDefData, Data_Owner, Data_NotOwner }; bool OwnsDefinitionData = false; if (D->DefinitionData) { assert(D->DefinitionData->Definition && "DefinitionData don't point to a definition decl!"); OwnsDefinitionData = D->DefinitionData->Definition == D; if (OwnsDefinitionData) { Record.push_back(Data_Owner); } else { Record.push_back(Data_NotOwner); Writer.AddDeclRef(D->DefinitionData->Definition, Record); } } else Record.push_back(Data_NoDefData); VisitRecordDecl(D); if (OwnsDefinitionData) { assert(D->DefinitionData); struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; Record.push_back(Data.UserDeclaredConstructor); Record.push_back(Data.UserDeclaredCopyConstructor); Record.push_back(Data.UserDeclaredCopyAssignment); Record.push_back(Data.UserDeclaredDestructor); Record.push_back(Data.Aggregate); Record.push_back(Data.PlainOldData); Record.push_back(Data.Empty); Record.push_back(Data.Polymorphic); Record.push_back(Data.Abstract); Record.push_back(Data.HasTrivialConstructor); Record.push_back(Data.HasTrivialCopyConstructor); Record.push_back(Data.HasTrivialCopyAssignment); Record.push_back(Data.HasTrivialDestructor); Record.push_back(Data.ComputedVisibleConversions); Record.push_back(Data.DeclaredDefaultConstructor); Record.push_back(Data.DeclaredCopyConstructor); Record.push_back(Data.DeclaredCopyAssignment); Record.push_back(Data.DeclaredDestructor); Record.push_back(D->getNumBases()); for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), E = D->bases_end(); I != E; ++I) Writer.AddCXXBaseSpecifier(*I, Record); // FIXME: Make VBases lazily computed when needed to avoid storing them. Record.push_back(D->getNumVBases()); for (CXXRecordDecl::base_class_iterator I = D->vbases_begin(), E = D->vbases_end(); I != E; ++I) Writer.AddCXXBaseSpecifier(*I, Record); Writer.AddUnresolvedSet(Data.Conversions, Record); Writer.AddUnresolvedSet(Data.VisibleConversions, Record); // Data.Definition is written at the top. Writer.AddDeclRef(Data.FirstFriend, Record); } enum { CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization }; if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) { Record.push_back(CXXRecTemplate); Writer.AddDeclRef(TemplD, Record); } else if (MemberSpecializationInfo *MSInfo = D->getMemberSpecializationInfo()) { Record.push_back(CXXRecMemberSpecialization); Writer.AddDeclRef(MSInfo->getInstantiatedFrom(), Record); Record.push_back(MSInfo->getTemplateSpecializationKind()); Writer.AddSourceLocation(MSInfo->getPointOfInstantiation(), Record); } else { Record.push_back(CXXRecNotTemplate); } Code = pch::DECL_CXX_RECORD; } void PCHDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { VisitFunctionDecl(D); Record.push_back(D->size_overridden_methods()); for (CXXMethodDecl::method_iterator I = D->begin_overridden_methods(), E = D->end_overridden_methods(); I != E; ++I) Writer.AddDeclRef(*I, Record); Code = pch::DECL_CXX_METHOD; } void PCHDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { VisitCXXMethodDecl(D); Record.push_back(D->IsExplicitSpecified); Record.push_back(D->ImplicitlyDefined); Writer.AddCXXBaseOrMemberInitializers(D->BaseOrMemberInitializers, D->NumBaseOrMemberInitializers, Record); Code = pch::DECL_CXX_CONSTRUCTOR; } void PCHDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); Record.push_back(D->ImplicitlyDefined); Writer.AddDeclRef(D->OperatorDelete, Record); Code = pch::DECL_CXX_DESTRUCTOR; } void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { VisitCXXMethodDecl(D); Record.push_back(D->IsExplicitSpecified); Code = pch::DECL_CXX_CONVERSION; } void PCHDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { VisitDecl(D); Writer.AddSourceLocation(D->getColonLoc(), Record); Code = pch::DECL_ACCESS_SPEC; } void PCHDeclWriter::VisitFriendDecl(FriendDecl *D) { VisitDecl(D); Record.push_back(D->Friend.is()); if (D->Friend.is()) Writer.AddTypeSourceInfo(D->Friend.get(), Record); else Writer.AddDeclRef(D->Friend.get(), Record); Writer.AddDeclRef(D->NextFriend, Record); Writer.AddSourceLocation(D->FriendLoc, Record); Code = pch::DECL_FRIEND; } void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { VisitDecl(D); Record.push_back(D->getNumTemplateParameters()); for (unsigned i = 0, e = D->getNumTemplateParameters(); i != e; ++i) Writer.AddTemplateParameterList(D->getTemplateParameterList(i), Record); Record.push_back(D->getFriendDecl() != 0); if (D->getFriendDecl()) Writer.AddDeclRef(D->getFriendDecl(), Record); else Writer.AddTypeSourceInfo(D->getFriendType(), Record); Writer.AddSourceLocation(D->getFriendLoc(), Record); Code = pch::DECL_FRIEND_TEMPLATE; } void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) { VisitNamedDecl(D); Writer.AddDeclRef(D->getTemplatedDecl(), Record); Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); } void PCHDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { VisitTemplateDecl(D); Record.push_back(D->getIdentifierNamespace()); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); if (D->getPreviousDeclaration() == 0) { // This TemplateDecl owns the CommonPtr; write it. assert(D->isCanonicalDecl()); Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record); if (D->getInstantiatedFromMemberTemplate()) Record.push_back(D->isMemberSpecialization()); Writer.AddDeclRef(D->getCommonPtr()->Latest, Record); } else { RedeclarableTemplateDecl *First = D->getFirstDeclaration(); assert(First != D); // If this is a most recent redeclaration that is pointed to by a first decl // in a chained PCH, keep track of the association with the map so we can // update the first decl during PCH reading. if (First->getMostRecentDeclaration() == D && First->getPCHLevel() > D->getPCHLevel()) { assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end() && "The latest is already set"); Writer.FirstLatestDecls[First] = D; } } } void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); if (D->getPreviousDeclaration() == 0) { typedef llvm::FoldingSet CTSDSetTy; CTSDSetTy &CTSDSet = D->getSpecializations(); Record.push_back(CTSDSet.size()); for (CTSDSetTy::iterator I=CTSDSet.begin(), E = CTSDSet.end(); I!=E; ++I) { assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(&*I, Record); } typedef llvm::FoldingSet CTPSDSetTy; CTPSDSetTy &CTPSDSet = D->getPartialSpecializations(); Record.push_back(CTPSDSet.size()); for (CTPSDSetTy::iterator I=CTPSDSet.begin(), E=CTPSDSet.end(); I!=E; ++I) { assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(&*I, Record); } // InjectedClassNameType is computed, no need to write it. } Code = pch::DECL_CLASS_TEMPLATE; } void PCHDeclWriter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { VisitCXXRecordDecl(D); llvm::PointerUnion InstFrom = D->getSpecializedTemplateOrPartial(); if (InstFrom.is()) { Writer.AddDeclRef(InstFrom.get(), Record); } else { Writer.AddDeclRef(InstFrom.get(), Record); Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); } // Explicit info. Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record); if (D->getTypeAsWritten()) { Writer.AddSourceLocation(D->getExternLoc(), Record); Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record); } Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); Record.push_back(D->getSpecializationKind()); if (D->isCanonicalDecl()) { // When reading, we'll add it to the folding set of the following template. Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record); } Code = pch::DECL_CLASS_TEMPLATE_SPECIALIZATION; } void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { VisitClassTemplateSpecializationDecl(D); Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); Record.push_back(D->getNumTemplateArgsAsWritten()); for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i) Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record); Record.push_back(D->getSequenceNumber()); // These are read/set from/to the first declaration. if (D->getPreviousDeclaration() == 0) { Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); Record.push_back(D->isMemberSpecialization()); } Code = pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; } void PCHDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); if (D->getPreviousDeclaration() == 0) { // This FunctionTemplateDecl owns the CommonPtr; write it. // Write the function specialization declarations. Record.push_back(D->getSpecializations().size()); for (llvm::FoldingSet::iterator I = D->getSpecializations().begin(), E = D->getSpecializations().end() ; I != E; ++I) { assert(I->Function->isCanonicalDecl() && "Expected only canonical decls in set"); Writer.AddDeclRef(I->Function, Record); } } Code = pch::DECL_FUNCTION_TEMPLATE; } void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { VisitTypeDecl(D); Record.push_back(D->wasDeclaredWithTypename()); Record.push_back(D->isParameterPack()); Record.push_back(D->defaultArgumentWasInherited()); Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record); Code = pch::DECL_TEMPLATE_TYPE_PARM; } void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { VisitVarDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); // Rest of NonTypeTemplateParmDecl. Record.push_back(D->getDefaultArgument() != 0); if (D->getDefaultArgument()) { Writer.AddStmt(D->getDefaultArgument()); Record.push_back(D->defaultArgumentWasInherited()); } Code = pch::DECL_NON_TYPE_TEMPLATE_PARM; } void PCHDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { VisitTemplateDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); // Rest of TemplateTemplateParmDecl. Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); Record.push_back(D->defaultArgumentWasInherited()); Code = pch::DECL_TEMPLATE_TEMPLATE_PARM; } void PCHDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAssertExpr()); Writer.AddStmt(D->getMessage()); Code = pch::DECL_STATIC_ASSERT; } /// \brief Emit the DeclContext part of a declaration context decl. /// /// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL /// block for this declaration context is stored. May be 0 to indicate /// that there are no declarations stored within this context. /// /// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE /// block for this declaration context is stored. May be 0 to indicate /// that there are no declarations visible from this context. Note /// that this value will not be emitted for non-primary declaration /// contexts. void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, uint64_t VisibleOffset) { Record.push_back(LexicalOffset); Record.push_back(VisibleOffset); } template void PCHDeclWriter::VisitRedeclarable(Redeclarable *D) { enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest }; if (D->RedeclLink.getNext() == D) { Record.push_back(NoRedeclaration); } else { Record.push_back(D->RedeclLink.NextIsPrevious() ? PointsToPrevious : PointsToLatest); Writer.AddDeclRef(D->RedeclLink.getPointer(), Record); } T *First = D->getFirstDeclaration(); T *ThisDecl = static_cast(D); // If this is a most recent redeclaration that is pointed to by a first decl // in a chained PCH, keep track of the association with the map so we can // update the first decl during PCH reading. if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl && First->getPCHLevel() > ThisDecl->getPCHLevel()) { assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end() && "The latest is already set"); Writer.FirstLatestDecls[First] = ThisDecl; } } //===----------------------------------------------------------------------===// // PCHWriter Implementation //===----------------------------------------------------------------------===// void PCHWriter::WriteDeclsBlockAbbrevs() { using namespace llvm; // Abbreviation for DECL_PARM_VAR. BitCodeAbbrev *Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(pch::DECL_PARM_VAR)); // Decl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // PCH level // NamedDecl Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // StorageClass Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo // ParmVarDecl Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv); Abv = new BitCodeAbbrev(); Abv->Add(BitCodeAbbrevOp(pch::DECL_CONTEXT_LEXICAL)); Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); DeclContextLexicalAbbrev = Stream.EmitAbbrev(Abv); } /// isRequiredDecl - Check if this is a "required" Decl, which must be seen by /// consumers of the AST. /// /// Such decls will always be deserialized from the PCH file, so we would like /// this to be as restrictive as possible. Currently the predicate is driven by /// code generation requirements, if other clients have a different notion of /// what is "required" then we may have to consider an alternate scheme where /// clients can iterate over the top-level decls and get information on them, /// without necessary deserializing them. We could explicitly require such /// clients to use a separate API call to "realize" the decl. This should be /// relatively painless since they would presumably only do it for top-level /// decls. static bool isRequiredDecl(const Decl *D, ASTContext &Context) { // File scoped assembly or obj-c implementation must be seen. if (isa(D) || isa(D)) return true; return Context.DeclMustBeEmitted(D); } void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { RecordData Record; PCHDeclWriter W(*this, Context, Record); // If this declaration is also a DeclContext, write blocks for the // declarations that lexically stored inside its context and those // declarations that are visible from its context. These blocks // are written before the declaration itself so that we can put // their offsets into the record for the declaration. uint64_t LexicalOffset = 0; uint64_t VisibleOffset = 0; DeclContext *DC = dyn_cast(D); if (DC) { LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); } // Determine the ID for this declaration pch::DeclID &IDR = DeclIDs[D]; if (IDR == 0) IDR = NextDeclID++; pch::DeclID ID = IDR; if (ID < FirstDeclID) { // We're replacing a decl in a previous file. ReplacedDecls.push_back(std::make_pair(ID, Stream.GetCurrentBitNo())); } else { unsigned Index = ID - FirstDeclID; // Record the offset for this declaration if (DeclOffsets.size() == Index) DeclOffsets.push_back(Stream.GetCurrentBitNo()); else if (DeclOffsets.size() < Index) { DeclOffsets.resize(Index+1); DeclOffsets[Index] = Stream.GetCurrentBitNo(); } } // Build and emit a record for this declaration Record.clear(); W.Code = (pch::DeclCode)0; W.AbbrevToUse = 0; W.Visit(D); if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); if (!W.Code) llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); // If the declaration had any attributes, write them now. if (D->hasAttrs()) WriteAttributeRecord(D->getAttrs()); // Flush any expressions that were written as part of this declaration. FlushStmts(); // Note "external" declarations so that we can add them to a record in the // PCH file later. // // FIXME: This should be renamed, the predicate is much more complicated. if (isRequiredDecl(D, Context)) ExternalDefinitions.push_back(ID); }