When building a PCH file, don't perform end-of-translation-unit
wrap-up (e.g., turning tentative definitions into definitions). Also,
very that, when we actually use the PCH file, we get the ride code
generation for tentative definitions and definitions that show up in
the PCH file.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69043 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Sema/ParseAST.h b/include/clang/Sema/ParseAST.h
index 8824600..bdce5e9 100644
--- a/include/clang/Sema/ParseAST.h
+++ b/include/clang/Sema/ParseAST.h
@@ -19,12 +19,18 @@
   class ASTConsumer;
   class ASTContext;
 
-  /// ParseAST - Parse the entire file specified, notifying the ASTConsumer as
-  /// the file is parsed.    This inserts the parsed decls into the translation unit
-  /// held by Ctx.
+  /// \brief Parse the entire file specified, notifying the ASTConsumer as
+  /// the file is parsed.
   ///
+  /// This operation inserts the parsed decls into the translation
+  /// unit held by Ctx.
+  ///
+  /// \param CompleteTranslationUnit When true, the parsed file is
+  /// considered to be a complete translation unit, and any
+  /// end-of-translation-unit wrapup will be performed.
   void ParseAST(Preprocessor &pp, ASTConsumer *C, 
-                ASTContext &Ctx, bool PrintStats = false);
+                ASTContext &Ctx, bool PrintStats = false,
+                bool CompleteTranslationUnit = true);
 
 }  // end namespace clang
 
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index bb5acb0..d237f75 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -29,14 +29,15 @@
 /// held by Ctx.
 ///
 void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
-                     ASTContext &Ctx, bool PrintStats) {
+                     ASTContext &Ctx, bool PrintStats,
+                     bool CompleteTranslationUnit) {
   // Collect global stats on Decls/Stmts (until we have a module streamer).
   if (PrintStats) {
     Decl::CollectingStats(true);
     Stmt::CollectingStats(true);
   }
 
-  Sema S(PP, Ctx, *Consumer);
+  Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit);
   Parser P(PP, S);
   PP.EnterMainSourceFile();
     
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index f11ce20..403e8f6 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -151,12 +151,14 @@
   Context.setObjCIdType(IdTypedef);
 }
 
-Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
+Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
+           bool CompleteTranslationUnit)
   : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
     Diags(PP.getDiagnostics()),
     SourceMgr(PP.getSourceManager()), CurContext(0), PreDeclaratorDC(0),
     CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
-    GlobalNewDeleteDeclared(false) {
+    GlobalNewDeleteDeclared(false), 
+    CompleteTranslationUnit(CompleteTranslationUnit) {
   
   // Get IdentifierInfo objects for known functions for which we
   // do extra checking.  
@@ -216,6 +218,9 @@
 /// translation unit when EOF is reached and all but the top-level scope is
 /// popped.
 void Sema::ActOnEndOfTranslationUnit() {
+  if (!CompleteTranslationUnit)
+    return;
+
   // C99 6.9.2p2:
   //   A declaration of an identifier for an object that has file
   //   scope without an initializer, and without a storage-class
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f48e75a..d642287 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -214,7 +214,18 @@
   /// A flag to remember whether the implicit forms of operator new and delete
   /// have been declared.
   bool GlobalNewDeleteDeclared;
-  
+
+  /// \brief Whether the code handled by Sema should be considered a
+  /// complete translation unit or not.
+  ///
+  /// When true (which is generally the case), Sema will perform
+  /// end-of-translation-unit semantic tasks (such as creating
+  /// initializers for tentative definitions in C) once parsing has
+  /// completed. This flag will be false when building PCH files,
+  /// since a PCH file is by definition not a complete translation
+  /// unit.
+  bool CompleteTranslationUnit;
+
   /// ObjCMethodList - a linked list of methods with different signatures.
   struct ObjCMethodList {
     ObjCMethodDecl *Method;
@@ -239,7 +250,8 @@
   /// Private Helper predicate to check for 'self'.
   bool isSelfExpr(Expr *RExpr);
 public:
-  Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer);
+  Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
+       bool CompleteTranslationUnit = true);
   ~Sema() {
     if (PackContext) FreePackedContext();
   }
diff --git a/test/PCH/external-defs.c b/test/PCH/external-defs.c
index 7be6c73..fd14c4f 100644
--- a/test/PCH/external-defs.c
+++ b/test/PCH/external-defs.c
@@ -2,7 +2,20 @@
 // RUN: clang-cc -triple x86_64-apple-darwin9 -emit-pch -o %t.pch %S/external-defs.h &&
 // RUN: clang-cc -triple x86_64-apple-darwin9 -include-pch %t.pch -emit-llvm -o %t %s &&
 
-// RUN: grep "@x = common global i32 0, align 4" %t | count 1 &&
+// RUN: grep "@x = common global i32 0" %t | count 1 &&
 // FIXME below: should be i32 17, but we don't serialize y's value yet
-// RUN: grep "@y = common global i32 0, align 4"  %t | count 1 &&
-// RUN: grep "@z" %t | count 0
+// RUN: grep "@y = common global i32 0"  %t | count 1 &&
+// RUN: grep "@z" %t | count 0 &&
+
+// RUN: grep "@x2 = global i32 19" %t | count 1 &&
+int x2 = 19;
+
+// RUN: grep "@incomplete_array = common global .*1 x i32" %t | count 1 &&
+// RUN: grep "@incomplete_array2 = common global .*17 x i32" %t | count 1 &&
+int incomplete_array2[17];
+// RUN: grep "@incomplete_array3 = common global .*1 x i32" %t | count 1
+int incomplete_array3[];
+
+struct S {
+  int x, y;
+};
diff --git a/test/PCH/external-defs.h b/test/PCH/external-defs.h
index 29345e9..4ac9077 100644
--- a/test/PCH/external-defs.h
+++ b/test/PCH/external-defs.h
@@ -1,10 +1,17 @@
 // Helper for external-defs.c test
 
-// Tentative definition
+// Tentative definitions
 int x;
+int x2;
 
 // FIXME: check this, once we actually serialize it
 int y = 17;
 
 // Should not show up
 static int z;
+
+int incomplete_array[];
+int incomplete_array2[];
+
+// FIXME: CodeGen problems prevents this from working (<rdar://problem/6762287>)
+// struct S s;
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp
index 91b87f2..3360649 100644
--- a/tools/clang-cc/clang-cc.cpp
+++ b/tools/clang-cc/clang-cc.cpp
@@ -1912,6 +1912,7 @@
   llvm::OwningPtr<ASTConsumer> Consumer;
   bool ClearSourceMgr = false;
   FixItRewriter *FixItRewrite = 0;
+  bool CompleteTranslationUnit = true;
 
   switch (PA) {
   default:
@@ -1925,6 +1926,8 @@
       return;
     }
 
+    if (ProgAction == GeneratePCH)
+      CompleteTranslationUnit = false;
     break;
       
   case DumpRawTokens: {
@@ -2098,7 +2101,8 @@
         return;
     }
 
-    ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats);
+    ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats, 
+             CompleteTranslationUnit);
     
     if (FixItRewrite)
       FixItRewrite->WriteFixedFile(InFile, OutputFile);