diff --git a/clang/include/clang/Sema/ParseAST.h b/clang/include/clang/Sema/ParseAST.h index 882460029d9f..bdce5e95effb 100644 --- a/clang/include/clang/Sema/ParseAST.h +++ b/clang/include/clang/Sema/ParseAST.h @@ -19,12 +19,18 @@ namespace clang { 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/clang/lib/Sema/ParseAST.cpp b/clang/lib/Sema/ParseAST.cpp index bb5acb0ee8da..d237f7539e4d 100644 --- a/clang/lib/Sema/ParseAST.cpp +++ b/clang/lib/Sema/ParseAST.cpp @@ -29,14 +29,15 @@ using namespace clang; /// 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/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index f11ce2043a8a..403e8f60f561 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -151,12 +151,14 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { 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 @@ void Sema::DeleteStmt(StmtTy *S) { /// 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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index f48e75afb353..d64228794bdf 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -214,7 +214,18 @@ public: /// 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 @@ public: /// 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/clang/test/PCH/external-defs.c b/clang/test/PCH/external-defs.c index 7be6c73bc757..fd14c4fa8b35 100644 --- a/clang/test/PCH/external-defs.c +++ b/clang/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/clang/test/PCH/external-defs.h b/clang/test/PCH/external-defs.h index 29345e9c6979..4ac9077d1213 100644 --- a/clang/test/PCH/external-defs.h +++ b/clang/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 () +// struct S s; diff --git a/clang/tools/clang-cc/clang-cc.cpp b/clang/tools/clang-cc/clang-cc.cpp index 91b87f2b0573..336064947570 100644 --- a/clang/tools/clang-cc/clang-cc.cpp +++ b/clang/tools/clang-cc/clang-cc.cpp @@ -1912,6 +1912,7 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, llvm::OwningPtr Consumer; bool ClearSourceMgr = false; FixItRewriter *FixItRewrite = 0; + bool CompleteTranslationUnit = true; switch (PA) { default: @@ -1925,6 +1926,8 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, return; } + if (ProgAction == GeneratePCH) + CompleteTranslationUnit = false; break; case DumpRawTokens: { @@ -2098,7 +2101,8 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, return; } - ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats); + ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats, + CompleteTranslationUnit); if (FixItRewrite) FixItRewrite->WriteFixedFile(InFile, OutputFile);