diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseAST.cpp | 54 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 4 |
4 files changed, 41 insertions, 20 deletions
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index ed920eb4880..783e073e665 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -407,6 +407,7 @@ SourceManager::~SourceManager() { void SourceManager::clearIDTables() { MainFileID = FileID(); + PredefinesFileID = FileID(); LocalSLocEntryTable.clear(); LoadedSLocEntryTable.clear(); SLocEntryLoaded.clear(); diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index d387f4392de..955c39cfe78 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -425,7 +425,7 @@ void Preprocessor::EnterMainSourceFile() { llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBufferCopy(Predefines, "<built-in>"); assert(SB && "Cannot create predefined source buffer"); - FileID FID = SourceMgr.createFileIDForMemBuffer(SB); + FileID FID = SourceMgr.createPredefinesFileIDForMemBuffer(SB); assert(!FID.isInvalid() && "Could not create FileID for predefines?"); // Start parsing the predefines. diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index d1c2624f8cb..3f86c4d2c89 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/ParseAST.h" +#include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/Sema.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/SemaConsumer.h" @@ -77,27 +78,50 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); S.Initialize(); - - if (ExternalASTSource *External = S.getASTContext().getExternalSource()) + + // C11 6.9p1 says translation units must have at least one top-level + // declaration. C++ doesn't have this restriction. We also don't want to + // complain if we have a precompiled header, although technically if the PCH + // is empty we should still emit the (pedantic) diagnostic. + bool WarnForEmptyTU = !S.getLangOpts().CPlusPlus; + if (ExternalASTSource *External = S.getASTContext().getExternalSource()) { External->StartTranslationUnit(Consumer); - - bool Abort = false; + WarnForEmptyTU = false; + } + + // Clang's predefines contain top-level declarations for things like va_list, + // making it hard to tell if the /user's/ translation unit has at least one + // top-level declaration. So we parse cautiously, looking for a declaration + // that doesn't come from our predefines. + // Note that ParseTopLevelDecl returns 'true' at EOF. + SourceManager &SM = S.getSourceManager(); Parser::DeclGroupPtrTy ADecl; - - while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. + while (WarnForEmptyTU && !P.ParseTopLevelDecl(ADecl)) { if (ADecl) { - if (!Consumer->HandleTopLevelDecl(ADecl.get())) { - Abort = true; - break; + if (!Consumer->HandleTopLevelDecl(ADecl.get())) + return; + if (DeclGroupRef::iterator FirstDecl = ADecl.get().begin()) { + SourceLocation DeclLoc = (*FirstDecl)->getLocation(); + WarnForEmptyTU = SM.isFromPredefines(DeclLoc); } } - }; + } - if (Abort) - return; + // If we ended up seeing EOF before any top-level declarations, emit our + // diagnostic. Otherwise, parse the rest of the file normally. + if (WarnForEmptyTU) { + P.Diag(diag::ext_empty_translation_unit); + } else { + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl) { + if (!Consumer->HandleTopLevelDecl(ADecl.get())) + return; + } + }; + } // Process any TopLevelDecls generated by #pragma weak. for (SmallVector<Decl*,2>::iterator diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 504071405b7..f0e2b3aa85f 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -439,10 +439,6 @@ void Parser::Initialize() { // Prime the lexer look-ahead. ConsumeToken(); - if (Tok.is(tok::eof) && - !getLangOpts().CPlusPlus) // Empty source file is an extension in C - Diag(Tok, diag::ext_empty_source_file); - // Initialization for Objective-C context sensitive keywords recognition. // Referenced in Parser::ParseObjCTypeQualifierList. if (getLangOpts().ObjC1) { |