[PCH] Fix a regression that r139441 introduced (decls were getting passed
to the consumer without being fully deserialized).

The regression was on compiling boost.python and it was too difficult to get a reduced
test case unfortunately.

Also modify the logic of how objc methods are getting passed to the consumer;
codegen depended on receiving objc methods before the implementation decl.
Since the interesting objc methods are ones with a body and such methods only
exist inside an ObjCImplDecl, deserialize and pass to consumer all the methods
of ObCImplDecl when we see one.

Fixes http://llvm.org/PR10922 & rdar://10117105.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139644 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8131c4b..50a3942 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -6387,7 +6387,7 @@
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
     if (!VD->isFileVarDecl())
       return false;
-  } else if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D))
+  } else if (!isa<FunctionDecl>(D))
     return false;
 
   // Weak references don't produce any output by themselves.
@@ -6427,9 +6427,6 @@
       return false;
     return true;
   }
-
-  if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D))
-    return Method->hasBody();
   
   const VarDecl *VD = cast<VarDecl>(D);
   assert(VD->isFileVarDecl() && "Expected file scoped var");
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 429edf9..77f4fb8 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4142,12 +4142,31 @@
   return const_cast<DeclContext*>(DC)->lookup(Name);
 }
 
+/// \brief Under non-PCH compilation the consumer receives the objc methods
+/// before receiving the implementation, and codegen depends on this.
+/// We simulate this by deserializing and passing to consumer the methods of the
+/// implementation before passing the deserialized implementation decl.
+static void PassObjCImplDeclToConsumer(ObjCImplDecl *ImplD,
+                                       ASTConsumer *Consumer) {
+  assert(ImplD && Consumer);
+
+  for (ObjCImplDecl::method_iterator
+         I = ImplD->meth_begin(), E = ImplD->meth_end(); I != E; ++I)
+    Consumer->HandleInterestingDecl(DeclGroupRef(*I));
+
+  Consumer->HandleInterestingDecl(DeclGroupRef(ImplD));
+}
+
 void ASTReader::PassInterestingDeclsToConsumer() {
   assert(Consumer);
   while (!InterestingDecls.empty()) {
-    DeclGroupRef DG(InterestingDecls.front());
+    Decl *D = InterestingDecls.front();
     InterestingDecls.pop_front();
-    Consumer->HandleInterestingDecl(DG);
+
+    if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+      PassObjCImplDeclToConsumer(ImplD, Consumer);
+    else
+      Consumer->HandleInterestingDecl(DeclGroupRef(D));
   }
 }
 
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index b794938..4448889 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1393,6 +1393,9 @@
 /// code generation, e.g., inline function definitions, Objective-C
 /// declarations with metadata, etc.
 static bool isConsumerInterestedIn(Decl *D) {
+  // An ObjCMethodDecl is never considered as "interesting" because its
+  // implementation container always is.
+
   if (isa<FileScopeAsmDecl>(D) || 
       isa<ObjCProtocolDecl>(D) || 
       isa<ObjCImplDecl>(D))
@@ -1402,8 +1405,6 @@
            Var->isThisDeclarationADefinition() == VarDecl::Definition;
   if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
     return Func->doesThisDeclarationHaveABody();
-  if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D))
-    return Method->hasBody();
   
   return false;
 }
@@ -1737,14 +1738,8 @@
   // 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 (Consumer) {
-      DeclGroupRef DG(D);
-      Consumer->HandleInterestingDecl(DG);
-    } else {
+  if (isConsumerInterestedIn(D))
       InterestingDecls.push_back(D);
-    }
-  }
   
   return D;
 }
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 55f1a6f..80685ad 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -1594,6 +1594,9 @@
 /// relatively painless since they would presumably only do it for top-level
 /// decls.
 static bool isRequiredDecl(const Decl *D, ASTContext &Context) {
+  // An ObjCMethodDecl is never considered as "required" because its
+  // implementation container always is.
+
   // File scoped assembly or obj-c implementation must be seen.
   if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D))
     return true;