|
12 | 12 | //===----------------------------------------------------------------------===//
|
13 | 13 |
|
14 | 14 | #include "clang/Parse/ParseAST.h"
|
| 15 | +#include "clang/Parse/ParseDiagnostic.h" |
15 | 16 | #include "clang/Sema/Sema.h"
|
16 | 17 | #include "clang/Sema/CodeCompleteConsumer.h"
|
17 | 18 | #include "clang/Sema/SemaConsumer.h"
|
@@ -77,27 +78,50 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
|
77 | 78 | S.getPreprocessor().EnterMainSourceFile();
|
78 | 79 | P.Initialize();
|
79 | 80 | S.Initialize();
|
80 |
| - |
81 |
| - if (ExternalASTSource *External = S.getASTContext().getExternalSource()) |
| 81 | + |
| 82 | + // C11 6.9p1 says translation units must have at least one top-level |
| 83 | + // declaration. C++ doesn't have this restriction. We also don't want to |
| 84 | + // complain if we have a precompiled header, although technically if the PCH |
| 85 | + // is empty we should still emit the (pedantic) diagnostic. |
| 86 | + bool WarnForEmptyTU = !S.getLangOpts().CPlusPlus; |
| 87 | + if (ExternalASTSource *External = S.getASTContext().getExternalSource()) { |
82 | 88 | External->StartTranslationUnit(Consumer);
|
83 |
| - |
84 |
| - bool Abort = false; |
| 89 | + WarnForEmptyTU = false; |
| 90 | + } |
| 91 | + |
| 92 | + // Clang's predefines contain top-level declarations for things like va_list, |
| 93 | + // making it hard to tell if the /user's/ translation unit has at least one |
| 94 | + // top-level declaration. So we parse cautiously, looking for a declaration |
| 95 | + // that doesn't come from our predefines. |
| 96 | + // Note that ParseTopLevelDecl returns 'true' at EOF. |
| 97 | + SourceManager &SM = S.getSourceManager(); |
85 | 98 | Parser::DeclGroupPtrTy ADecl;
|
86 |
| - |
87 |
| - while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. |
88 |
| - // If we got a null return and something *was* parsed, ignore it. This |
89 |
| - // is due to a top-level semicolon, an action override, or a parse error |
90 |
| - // skipping something. |
| 99 | + while (WarnForEmptyTU && !P.ParseTopLevelDecl(ADecl)) { |
91 | 100 | if (ADecl) {
|
92 |
| - if (!Consumer->HandleTopLevelDecl(ADecl.get())) { |
93 |
| - Abort = true; |
94 |
| - break; |
| 101 | + if (!Consumer->HandleTopLevelDecl(ADecl.get())) |
| 102 | + return; |
| 103 | + if (DeclGroupRef::iterator FirstDecl = ADecl.get().begin()) { |
| 104 | + SourceLocation DeclLoc = (*FirstDecl)->getLocation(); |
| 105 | + WarnForEmptyTU = SM.isFromPredefines(DeclLoc); |
95 | 106 | }
|
96 | 107 | }
|
97 |
| - }; |
| 108 | + } |
98 | 109 |
|
99 |
| - if (Abort) |
100 |
| - return; |
| 110 | + // If we ended up seeing EOF before any top-level declarations, emit our |
| 111 | + // diagnostic. Otherwise, parse the rest of the file normally. |
| 112 | + if (WarnForEmptyTU) { |
| 113 | + P.Diag(diag::ext_empty_translation_unit); |
| 114 | + } else { |
| 115 | + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. |
| 116 | + // If we got a null return and something *was* parsed, ignore it. This |
| 117 | + // is due to a top-level semicolon, an action override, or a parse error |
| 118 | + // skipping something. |
| 119 | + if (ADecl) { |
| 120 | + if (!Consumer->HandleTopLevelDecl(ADecl.get())) |
| 121 | + return; |
| 122 | + } |
| 123 | + }; |
| 124 | + } |
101 | 125 |
|
102 | 126 | // Process any TopLevelDecls generated by #pragma weak.
|
103 | 127 | for (SmallVector<Decl*,2>::iterator
|
|
0 commit comments