In standard C since C89, a 'translation-unit' is syntactically defined to have at least one "external-declaration", which is either a decl or a function definition. In Clang the latter gives us a declaration as well. The tricky bit about this warning is that our predefines can contain external declarations (__builtin_va_list and the 128-bit integer types). Therefore our AST parser now makes sure we have at least one declaration that doesn't come from the predefines buffer. Also, remove bogus warning about empty source files. This doesn't catch source files that only contain comments, and never fired anyway because of our predefines. PR12665 and <rdar://problem/9165548> llvm-svn: 158085
144 lines
5.1 KiB
C++
144 lines
5.1 KiB
C++
//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the clang::ParseAST method.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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"
|
|
#include "clang/Sema/ExternalSemaSource.h"
|
|
#include "clang/AST/ASTConsumer.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/ExternalASTSource.h"
|
|
#include "clang/AST/Stmt.h"
|
|
#include "clang/Parse/Parser.h"
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/Support/CrashRecoveryContext.h"
|
|
#include <cstdio>
|
|
|
|
using namespace clang;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Public interface to the file
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// 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.
|
|
///
|
|
void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
|
|
ASTContext &Ctx, bool PrintStats,
|
|
TranslationUnitKind TUKind,
|
|
CodeCompleteConsumer *CompletionConsumer,
|
|
bool SkipFunctionBodies) {
|
|
|
|
OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
|
|
TUKind,
|
|
CompletionConsumer));
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
|
|
|
|
ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
|
|
}
|
|
|
|
void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
|
|
// Collect global stats on Decls/Stmts (until we have a module streamer).
|
|
if (PrintStats) {
|
|
Decl::EnableStatistics();
|
|
Stmt::EnableStatistics();
|
|
}
|
|
|
|
// Also turn on collection of stats inside of the Sema object.
|
|
bool OldCollectStats = PrintStats;
|
|
std::swap(OldCollectStats, S.CollectStats);
|
|
|
|
ASTConsumer *Consumer = &S.getASTConsumer();
|
|
|
|
OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
|
|
SkipFunctionBodies));
|
|
Parser &P = *ParseOP.get();
|
|
|
|
PrettyStackTraceParserEntry CrashInfo(P);
|
|
|
|
// Recover resources if we crash before exiting this method.
|
|
llvm::CrashRecoveryContextCleanupRegistrar<Parser>
|
|
CleanupParser(ParseOP.get());
|
|
|
|
S.getPreprocessor().EnterMainSourceFile();
|
|
P.Initialize();
|
|
S.Initialize();
|
|
|
|
// 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);
|
|
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 (WarnForEmptyTU && !P.ParseTopLevelDecl(ADecl)) {
|
|
if (ADecl) {
|
|
if (!Consumer->HandleTopLevelDecl(ADecl.get()))
|
|
return;
|
|
if (DeclGroupRef::iterator FirstDecl = ADecl.get().begin()) {
|
|
SourceLocation DeclLoc = (*FirstDecl)->getLocation();
|
|
WarnForEmptyTU = SM.isFromPredefines(DeclLoc);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
I = S.WeakTopLevelDecls().begin(),
|
|
E = S.WeakTopLevelDecls().end(); I != E; ++I)
|
|
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
|
|
|
|
Consumer->HandleTranslationUnit(S.getASTContext());
|
|
|
|
std::swap(OldCollectStats, S.CollectStats);
|
|
if (PrintStats) {
|
|
llvm::errs() << "\nSTATISTICS:\n";
|
|
P.getActions().PrintStats();
|
|
S.getASTContext().PrintStats();
|
|
Decl::PrintStats();
|
|
Stmt::PrintStats();
|
|
Consumer->PrintStats();
|
|
}
|
|
}
|