From 2d68810caf26d40833abec26c1e6455669014147 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 2 Aug 2010 07:14:54 +0000 Subject: [PATCH] Read/write in PCH Sema's StdNamespace and StdBadAlloc and use a LazyDeclPtr for them that will deserialize them when needed. llvm-svn: 110031 --- clang/include/clang/AST/ExternalASTSource.h | 8 ++++++-- clang/include/clang/Frontend/PCHBitCodes.h | 5 ++++- clang/include/clang/Frontend/PCHReader.h | 3 +++ clang/lib/Frontend/PCHReader.cpp | 16 ++++++++++++++++ clang/lib/Frontend/PCHWriter.cpp | 11 +++++++++++ clang/lib/Sema/Sema.cpp | 3 +-- clang/lib/Sema/Sema.h | 14 ++++++++++++-- clang/lib/Sema/SemaDecl.cpp | 6 +++--- clang/lib/Sema/SemaDeclCXX.cpp | 12 ++++++------ clang/lib/Sema/SemaExprCXX.cpp | 6 +++--- clang/test/PCH/cxx-typeid.cpp | 9 +++++++++ clang/test/PCH/cxx-typeid.h | 3 +++ 12 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 clang/test/PCH/cxx-typeid.cpp create mode 100644 clang/test/PCH/cxx-typeid.h diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 4a6377eaa95b..d23e75dd3810 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -172,7 +172,7 @@ protected: /// The AST node is identified within the external AST source by a /// 63-bit offset, and can be retrieved via an operation on the /// external AST source itself. -template +template struct LazyOffsetPtr { /// \brief Either a pointer to an AST node or the offset within the /// external AST source where the AST node can be found. @@ -230,9 +230,13 @@ public: }; /// \brief A lazy pointer to a statement. -typedef LazyOffsetPtr +typedef LazyOffsetPtr LazyDeclStmtPtr; +/// \brief A lazy pointer to a declaration. +typedef LazyOffsetPtr + LazyDeclPtr; + } // end namespace clang #endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index 774a96becb98..109a78bd8849 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -243,7 +243,10 @@ namespace clang { /// \brief Record code for an update to the TU's lexically contained /// declarations. - TU_UPDATE_LEXICAL = 28 + TU_UPDATE_LEXICAL = 28, + + /// \brief Record code for declarations that Sema keeps references of. + SEMA_DECL_REFS = 29 }; /// \brief Record types used within a source manager block. diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 57af01033a5d..87c7624be09e 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -391,6 +391,9 @@ private: /// \brief The set of dynamic CXXRecord declarations stored in the PCH file. llvm::SmallVector DynamicClasses; + /// \brief The set of Sema declaration references, stored in PCH. + llvm::SmallVector SemaDeclRefs; + /// \brief The set of Objective-C category definitions stored in the /// the PCH file. llvm::SmallVector ObjCCategoryImpls; diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 5a239e4f045b..0502e674a9d9 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -1728,6 +1728,14 @@ PCHReader::ReadPCHBlock(PerFileData &F) { DynamicClasses.swap(Record); break; + case pch::SEMA_DECL_REFS: + if (!SemaDeclRefs.empty()) { + Error("duplicate SEMA_DECL_REFS record in PCH file"); + return Failure; + } + SemaDeclRefs.swap(Record); + break; + case pch::ORIGINAL_FILE_NAME: // The primary PCH will be the last to get here, so it will be the one // that's used. @@ -3152,6 +3160,14 @@ void PCHReader::InitializeSema(Sema &S) { SemaObj->DynamicClasses.push_back( cast(GetDecl(DynamicClasses[I]))); + // Load the offsets of the declarations that Sema references. + // They will be lazily deserialized when needed. + if (!SemaDeclRefs.empty()) { + assert(SemaDeclRefs.size() == 2 && "More decl refs than expected!"); + SemaObj->StdNamespace = SemaDeclRefs[0]; + SemaObj->StdBadAlloc = SemaDeclRefs[1]; + } + // If there are @selector references added them to its pool. This is for // implementation of -Wselector. PerFileData &F = *Chain[0]; diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index a72f7cfea895..8bf85efd62b4 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -2243,6 +2243,13 @@ void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I) AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses); + // Build a record containing some declaration references. + RecordData SemaDeclRefs; + if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) { + AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs); + AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs); + } + // Write the remaining PCH contents. RecordData Record; Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5); @@ -2323,6 +2330,10 @@ void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, if (!DynamicClasses.empty()) Stream.EmitRecord(pch::DYNAMIC_CLASSES, DynamicClasses); + // Write the record containing declaration references of Sema. + if (!SemaDeclRefs.empty()) + Stream.EmitRecord(pch::SEMA_DECL_REFS, SemaDeclRefs); + // Some simple statistics Record.clear(); Record.push_back(NumStatements); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index a9a4f5290cf9..a42c6e804cf8 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -127,8 +127,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), PackContext(0), TopFunctionScope(0), ParsingDeclDepth(0), - IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), - GlobalNewDeleteDeclared(false), + IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), SuppressAccessChecking(false), NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0), diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 336dfa3763ee..85627b02b9d3 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -523,11 +523,11 @@ public: Scope *TUScope; /// \brief The C++ "std" namespace, where the standard library resides. - NamespaceDecl *StdNamespace; + LazyDeclPtr StdNamespace; /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. - CXXRecordDecl *StdBadAlloc; + LazyDeclPtr StdBadAlloc; /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. @@ -2167,7 +2167,17 @@ public: AttributeList *AttrList); virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace); + NamespaceDecl *getStdNamespace() const { + return cast_or_null( + StdNamespace.get(Context.getExternalSource())); + } NamespaceDecl *getOrCreateStdNamespace(); + + CXXRecordDecl *getStdBadAlloc() const { + return cast_or_null( + StdBadAlloc.get(Context.getExternalSource())); + } + virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 71572d89b6cc..8a656bcf16f3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5182,7 +5182,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (getLangOptions().CPlusPlus && Name && DC && StdNamespace && - DC->Equals(StdNamespace) && Name->isStr("bad_alloc")) { + DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) { // This is a declaration of or a reference to "std::bad_alloc". isStdBadAlloc = true; @@ -5190,7 +5190,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // std::bad_alloc has been implicitly declared (but made invisible to // name lookup). Fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. - Previous.addDecl(StdBadAlloc); + Previous.addDecl(getStdBadAlloc()); } } @@ -5481,7 +5481,7 @@ CreateNewDecl: New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, cast_or_null(PrevDecl)); - if (isStdBadAlloc && (!StdBadAlloc || StdBadAlloc->isImplicit())) + if (isStdBadAlloc && (!StdBadAlloc || getStdBadAlloc()->isImplicit())) StdBadAlloc = cast(New); } else New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index cf6e354f3c4d..a0bc5840cdb4 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3213,12 +3213,12 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, CurContext->getLookupContext()->isTranslationUnit()) { // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. - if (StdNamespace) { + if (NamespaceDecl *StdNS = getStdNamespace()) { // We had already defined a dummy namespace "std". Link this new // namespace definition to the dummy namespace "std". - StdNamespace->setNextNamespace(Namespc); - StdNamespace->setLocation(IdentLoc); - Namespc->setOriginalNamespace(StdNamespace->getOriginalNamespace()); + StdNS->setNextNamespace(Namespc); + StdNS->setLocation(IdentLoc); + Namespc->setOriginalNamespace(StdNS->getOriginalNamespace()); } // Make our StdNamespace cache point at the first real definition of the @@ -3320,10 +3320,10 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { Context.getTranslationUnitDecl(), SourceLocation(), &PP.getIdentifierTable().get("std")); - StdNamespace->setImplicit(true); + getStdNamespace()->setImplicit(true); } - return StdNamespace; + return getStdNamespace(); } Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index d607afac1665..8b2fc7e56a1e 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -343,7 +343,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, StdNamespace); + LookupQualifiedName(R, getStdNamespace()); RecordDecl *TypeInfoRecordDecl = R.getAsSingle(); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -1203,7 +1203,7 @@ void Sema::DeclareGlobalNewDelete() { SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), SourceLocation(), 0); - StdBadAlloc->setImplicit(true); + getStdBadAlloc()->setImplicit(true); } GlobalNewDeleteDeclared = true; @@ -1257,7 +1257,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { assert(StdBadAlloc && "Must have std::bad_alloc declared"); - BadAllocType = Context.getTypeDeclType(StdBadAlloc); + BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); } QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, diff --git a/clang/test/PCH/cxx-typeid.cpp b/clang/test/PCH/cxx-typeid.cpp new file mode 100644 index 000000000000..164b4bafe072 --- /dev/null +++ b/clang/test/PCH/cxx-typeid.cpp @@ -0,0 +1,9 @@ +// Test this without pch. +// RUN: %clang_cc1 -include %S/cxx-typeid.h -fsyntax-only -verify %s + +// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-typeid.h +// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s + +void f() { + (void)typeid(int); +} diff --git a/clang/test/PCH/cxx-typeid.h b/clang/test/PCH/cxx-typeid.h new file mode 100644 index 000000000000..aa3b16aa0b49 --- /dev/null +++ b/clang/test/PCH/cxx-typeid.h @@ -0,0 +1,3 @@ +// Header for PCH test cxx-typeid.cpp + +#include