diff options
-rw-r--r-- | include/clang/Basic/DiagnosticFrontendKinds.td | 2 | ||||
-rw-r--r-- | test/Frontend/ast-codegen.c | 5 | ||||
-rw-r--r-- | tools/clang-cc/clang-cc.cpp | 79 |
3 files changed, 83 insertions, 3 deletions
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 432b63a8b0..30193f1a87 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -15,6 +15,8 @@ def err_fe_unknown_target_abi : Error<"unknown target ABI '%0'">; def err_fe_error_reading : Error<"error reading '%0'">; def err_fe_error_reading_stdin : Error<"error reading stdin">; def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; +def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal; +def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal; def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; def note_fixit_in_macro : Note< diff --git a/test/Frontend/ast-codegen.c b/test/Frontend/ast-codegen.c new file mode 100644 index 0000000000..795be92a24 --- /dev/null +++ b/test/Frontend/ast-codegen.c @@ -0,0 +1,5 @@ +// RUN: clang -emit-ast -o %t.ast %s && +// RUN: clang -emit-llvm -S -o - %t.ast | FileCheck %s + +// CHECK: module asm "foo" +__asm__("foo"); diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 1adcfdb0ad..78a38c0f9f 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -24,6 +24,7 @@ #include "clang/Frontend/AnalysisConsumer.h" #include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompileOptions.h" #include "clang/Frontend/FixItRewriter.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -318,7 +319,8 @@ enum LangKind { langkind_objc_cpp, langkind_objcxx, langkind_objcxx_cpp, - langkind_ocl + langkind_ocl, + langkind_ast }; static llvm::cl::opt<LangKind> @@ -347,6 +349,8 @@ BaseLang("x", llvm::cl::desc("Base language to compile"), "C++ header"), clEnumValN(langkind_objcxx, "objective-c++-header", "Objective-C++ header"), + clEnumValN(langkind_ast, "ast", + "Clang AST"), clEnumValEnd)); static llvm::cl::opt<bool> @@ -402,7 +406,9 @@ static LangKind GetLanguage(llvm::StringRef Filename) { return BaseLang; llvm::StringRef Ext = Filename.rsplit('.').second; - if (Ext == "c") + if (Ext == "ast") + return langkind_ast; + else if (Ext == "c") return langkind_c; else if (Ext == "S" || Ext == "s") return langkind_asm_cpp; @@ -687,6 +693,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK, if (LangStd == lang_unspecified) { // Based on the base language, pick one. switch (LK) { + case langkind_ast: assert(0 && "Invalid call for AST inputs"); case lang_unspecified: assert(0 && "Unknown base language"); case langkind_ocl: LangStd = lang_c99; @@ -2116,6 +2123,65 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF, } } +/// ProcessInputFile - Process a single AST input file with the specified state. +/// +static void ProcessASTInputFile(const std::string &InFile, ProgActions PA, + const llvm::StringMap<bool> &Features, + Diagnostic &Diags, FileManager &FileMgr, + llvm::LLVMContext& Context) { + // FIXME: This is manufactoring its own diags and source manager, we should + // reuse ours. + std::string Error; + llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, FileMgr, + &Error)); + if (!AST) { + Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_file) << Error; + return; + } + + Preprocessor &PP = AST->getPreprocessor(); + + llvm::OwningPtr<llvm::raw_ostream> OS; + llvm::sys::Path OutPath; + llvm::OwningPtr<ASTConsumer> Consumer(CreateConsumerAction(PP, InFile, PA, OS, + OutPath, Features, + Context)); + + if (!Consumer.get()) { + Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_action); + return; + } + + // Stream the input AST to the consumer. + Consumer->Initialize(AST->getASTContext()); + AST->getASTContext() + .getExternalSource()->StartTranslationUnit(Consumer.get()); + Consumer->HandleTranslationUnit(AST->getASTContext()); + + // FIXME: Tentative decls and #pragma weak aren't going to get handled + // correctly here. + + // Release the consumer and the AST, in that order since the consumer may + // perform actions in its destructor which require the context. + if (DisableFree) { + Consumer.take(); + AST.take(); + } else { + Consumer.reset(); + AST.reset(); + } + + // Always delete the output stream because we don't want to leak file + // handles. Also, we don't want to try to erase an open file. + OS.reset(); + + if ((HadErrors || (PP.getDiagnostics().getNumErrors() != 0)) && + !OutPath.isEmpty()) { + // If we had errors, try to erase the output file. + OutPath.eraseFromDisk(); + } +} + static llvm::cl::list<std::string> InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input files>")); @@ -2258,6 +2324,14 @@ int main(int argc, char **argv) { for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) { const std::string &InFile = InputFilenames[i]; + LangKind LK = GetLanguage(InFile); + // AST inputs are handled specially. + if (LK == langkind_ast) { + ProcessASTInputFile(InFile, ProgAction, Features, + Diags, FileMgr, Context); + continue; + } + /// Create a SourceManager object. This tracks and owns all the file /// buffers allocated to a translation unit. if (!SourceMgr) @@ -2269,7 +2343,6 @@ int main(int argc, char **argv) { LangOptions LangInfo; DiagClient->setLangOptions(&LangInfo); - LangKind LK = GetLanguage(InFile); InitializeLangOptions(LangInfo, LK); InitializeLanguageStandard(LangInfo, LK, Target.get(), Features); |