aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td2
-rw-r--r--test/Frontend/ast-codegen.c5
-rw-r--r--tools/clang-cc/clang-cc.cpp79
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);