diff options
-rw-r--r-- | include/clang/AST/DeclObjC.h | 18 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 5 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 4 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 22 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 31 | ||||
-rw-r--r-- | test/Modules/Inputs/redecl-merge-left.h | 2 | ||||
-rw-r--r-- | test/Modules/Inputs/redecl-merge-right.h | 2 | ||||
-rw-r--r-- | test/Modules/Inputs/redecl-merge-top.h | 2 |
8 files changed, 61 insertions, 25 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index a1a287118e..459e9b3500 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -174,8 +174,7 @@ private: SourceLocation DeclEndLoc; // the location of the ';' or '{'. // The following are only used for method definitions, null otherwise. - // FIXME: space savings opportunity, consider a sub-class. - Stmt *Body; + LazyDeclStmtPtr Body; /// SelfDecl - Decl for the implicit self parameter. This is lazily /// constructed by createImplicitParams. @@ -242,7 +241,7 @@ private: SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), MethodDeclType(T), ResultTInfo(ResultTInfo), ParamsAndSelLocs(0), NumParams(0), - DeclEndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) { + DeclEndLoc(endLoc), Body(), SelfDecl(0), CmdDecl(0) { setImplicit(isImplicitlyDeclared); } @@ -427,10 +426,15 @@ public: return ImplementationControl(DeclImplementation); } - virtual Stmt *getBody() const { - return (Stmt*) Body; - } - CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; } + /// \brief Determine whether this method has a body. + virtual bool hasBody() const { return Body; } + + /// \brief Retrieve the body of this method, if it has one. + virtual Stmt *getBody() const; + + void setLazyBody(uint64_t Offset) { Body = Offset; } + + CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); } void setBody(Stmt *B) { Body = B; } /// \brief Returns whether this specific method is a definition. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 7bdd0a70dc..5136113f79 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -341,7 +341,10 @@ private: /// \brief The set of C++ or Objective-C classes that have forward /// declarations that have not yet been linked to their definitions. llvm::SmallPtrSet<Decl *, 4> PendingDefinitions; - + + /// \brief Functions or methods that have bodies that will be attached. + llvm::SmallDenseMap<Decl *, uint64_t, 4> PendingBodies; + /// \brief Read the records that describe the contents of declcontexts. bool ReadDeclContextStorage(ModuleFile &M, llvm::BitstreamCursor &Cursor, diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index d28a910d0a..45c57d6591 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -445,6 +445,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { Selector(), QualType(), 0, 0); } +Stmt *ObjCMethodDecl::getBody() const { + return Body.get(getASTContext().getExternalSource()); +} + void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) { assert(PrevMethod); getASTContext().setObjCMethodRedeclaration(PrevMethod, this); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 05a453143c..b37f8c2363 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -6477,9 +6477,29 @@ void ASTReader::finishPendingActions() { for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(), REnd = RTD->redecls_end(); R != REnd; ++R) - R->Common = RTD->Common; + R->Common = RTD->Common; } PendingDefinitions.clear(); + + // Load the bodies of any functions or methods we've encountered. We do + // this now (delayed) so that we can be sure that the declaration chains + // have been fully wired up. + for (llvm::SmallDenseMap<Decl *, uint64_t, 4>::iterator + PB = PendingBodies.begin(), PBEnd = PendingBodies.end(); + PB != PBEnd; ++PB) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) { + // FIXME: Check for =delete/=default? + // FIXME: Complain about ODR violations here? + if (!getContext().getLangOpts().Modules || !FD->hasBody()) + FD->setLazyBody(PB->second); + continue; + } + + ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first); + if (!getContext().getLangOpts().Modules || !MD->hasBody()) + MD->setLazyBody(PB->second); + } + PendingBodies.clear(); } void ASTReader::FinishedDeserializing() { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 762ad01b51..41d8ff98a1 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -47,6 +47,8 @@ namespace clang { DeclID DeclContextIDForTemplateParmDecl; DeclID LexicalDeclContextIDForTemplateParmDecl; + bool HasPendingBody; + uint64_t GetCurrentCursorOffset(); SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { @@ -198,11 +200,14 @@ namespace clang { const RecordData &Record, unsigned &Idx) : Reader(Reader), F(F), ThisDeclID(thisDeclID), RawLocation(RawLocation), Record(Record), Idx(Idx), - TypeIDForTypeDecl(0) { } + TypeIDForTypeDecl(0), HasPendingBody(false) { } static void attachPreviousDecl(Decl *D, Decl *previous); static void attachLatestDecl(Decl *D, Decl *latest); + /// \brief Determine whether this declaration has a pending body. + bool hasPendingBody() const { return HasPendingBody; } + void Visit(Decl *D); void UpdateDecl(Decl *D, ModuleFile &ModuleFile, @@ -324,9 +329,10 @@ void ASTDeclReader::Visit(Decl *D) { // module). // FIXME: Also consider = default and = delete. // FIXME: Can we diagnose ODR violations somehow? - if (Record[Idx++] && - (!Reader.getContext().getLangOpts().Modules || !FD->hasBody())) - FD->setLazyBody(GetCurrentCursorOffset()); + if (Record[Idx++]) { + Reader.PendingBodies[FD] = GetCurrentCursorOffset(); + HasPendingBody = true; + } } else if (D->isTemplateParameter()) { // If we have a fully initialized template parameter, we can now // set its DeclContext. @@ -634,13 +640,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { VisitNamedDecl(MD); if (Record[Idx++]) { - // In practice, this won't be executed (since method definitions - // don't occur in header files). - // Switch case IDs for this method body. - ASTReader::SwitchCaseMapTy SwitchCaseStmtsForObjCMethod; - SaveAndRestore<ASTReader::SwitchCaseMapTy *> - SCFOM(Reader.CurrSwitchCaseStmts, &SwitchCaseStmtsForObjCMethod); - MD->setBody(Reader.ReadStmt(F)); + // Load the body on-demand. Most clients won't care, because method + // definitions rarely show up in headers. + Reader.PendingBodies[MD] = GetCurrentCursorOffset(); + HasPendingBody = true; MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx)); MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx)); } @@ -1662,7 +1665,7 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) { /// This routine should return true for anything that might affect /// code generation, e.g., inline function definitions, Objective-C /// declarations with metadata, etc. -static bool isConsumerInterestedIn(Decl *D) { +static bool isConsumerInterestedIn(Decl *D, bool HasBody) { // An ObjCMethodDecl is never considered as "interesting" because its // implementation container always is. @@ -1674,7 +1677,7 @@ static bool isConsumerInterestedIn(Decl *D) { return Var->isFileVarDecl() && Var->isThisDeclarationADefinition() == VarDecl::Definition; if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) - return Func->doesThisDeclarationHaveABody(); + return Func->doesThisDeclarationHaveABody() || HasBody; return false; } @@ -2162,7 +2165,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // 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)) + if (isConsumerInterestedIn(D, Reader.hasPendingBody())) InterestingDecls.push_back(D); return D; diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h index ee794ff320..5e6d2e512b 100644 --- a/test/Modules/Inputs/redecl-merge-left.h +++ b/test/Modules/Inputs/redecl-merge-left.h @@ -60,7 +60,7 @@ typedef int T1; typedef float T2; int func0(int); -int func1(int); +int func1(int x) { return x; } int func2(int); diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h index f62020f205..20223083c3 100644 --- a/test/Modules/Inputs/redecl-merge-right.h +++ b/test/Modules/Inputs/redecl-merge-right.h @@ -65,7 +65,7 @@ typedef double T2; int func0(int); int func1(int); int func1(int); -int func1(int); +int func1(int x) { return x; } int func1(int); static int func2(int); diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h index 25456deb28..690e6df1c9 100644 --- a/test/Modules/Inputs/redecl-merge-top.h +++ b/test/Modules/Inputs/redecl-merge-top.h @@ -14,3 +14,5 @@ struct S1; struct S2; struct S2; + +int func1(int); |