]> granicus.if.org Git - clang/commitdiff
When we load a function or method body from an AST file, we check
authorDouglas Gregor <dgregor@apple.com>
Tue, 9 Oct 2012 17:21:28 +0000 (17:21 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 9 Oct 2012 17:21:28 +0000 (17:21 +0000)
whether that function/method already has a body (loaded from some
other AST file), as introduced in r165137. Delay this check until
after the redeclaration chains have been wired up.

While I'm here, make the loading of method bodies lazy.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165513 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclObjC.h
include/clang/Serialization/ASTReader.h
lib/AST/DeclObjC.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
test/Modules/Inputs/redecl-merge-left.h
test/Modules/Inputs/redecl-merge-right.h
test/Modules/Inputs/redecl-merge-top.h

index a1a287118e8cbcdcb4efee4ab548826ea2c040aa..459e9b35009a8392e26e5ada0a83acfe97bca1ec 100644 (file)
@@ -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.
index 7bdd0a70dc14d17d6f37c0fe84b2fe80cec67379..5136113f7920c13bb003b105ff31b9a421d480f7 100644 (file)
@@ -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,
index d28a910d0a53e8243379fb87ef21522c4a62f2f8..45c57d6591009c0b1c781091d1671869d65ea287 100644 (file)
@@ -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);
index 05a453143c7df9bad7d11322707425a0862ffb67..b37f8c23631896cbfb99678e4589f32a9e5d1113 100644 (file)
@@ -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() {
index 762ad01b51e39e1f35fd909991d2ae7f239e59de..41d8ff98a1cfe02159f51ece2f9a6dbf8bf6c792 100644 (file)
@@ -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;
index ee794ff320efccd9066e3acf2ad0c6a5eae8c74c..5e6d2e512b0090dd66e361cff912cd0c4d89099f 100644 (file)
@@ -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);
 
 
index f62020f2051c6ef06d426faf3b21d3fdc7740d08..20223083c31aacdde122574283ab651201d253ac 100644 (file)
@@ -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);
 
index 25456deb28df45dfc75c70875d9ed32c7f341da4..690e6df1c9e2c979a44b308e3932542ff49fcb69 100644 (file)
@@ -14,3 +14,5 @@
 struct S1;
 struct S2;
 struct S2;
+
+int func1(int);