summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Basic/SourceManager.cpp1
-rw-r--r--clang/lib/Lex/Preprocessor.cpp2
-rw-r--r--clang/lib/Parse/ParseAST.cpp54
-rw-r--r--clang/lib/Parse/Parser.cpp4
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) {
OpenPOWER on IntegriCloud