Add driver support for -emit-ast and AST compilation steps.
- <rdar://problem/7185031> Add 'clang' option '-emit-ast'
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80678 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index a8dbd68..486bfb3 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -43,6 +43,8 @@
"invalid version number in '%0'">;
def err_drv_no_linker_llvm_support : Error<
"'%0': unable to pass LLVM bit-code files to linker">;
+def err_drv_no_ast_support : Error<
+ "'%0': unable to use AST files with this tool">;
def err_drv_clang_unsupported : Error<
"the clang compiler does not support '%0'">;
def err_drv_command_failed : Error<
diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def
index aa10bbf..72bc907 100644
--- a/include/clang/Driver/Options.def
+++ b/include/clang/Driver/Options.def
@@ -353,6 +353,8 @@
OPTION("-dynamic", dynamic, Flag, INVALID, INVALID, "q", 0, 0, 0)
OPTION("-d", d_Flag, Flag, d_Group, INVALID, "", 0, 0, 0)
OPTION("-d", d_Joined, Joined, d_Group, INVALID, "", 0, 0, 0)
+OPTION("-emit-ast", emit_ast, Flag, INVALID, INVALID, "", 0,
+ "Emit Clang AST files for source inputs", 0)
OPTION("-emit-llvm", emit_llvm, Flag, INVALID, INVALID, "", 0,
"Use the LLVM representation for assembler and object files", 0)
OPTION("-exported_symbols_list", exported__symbols__list, Separate, INVALID, INVALID, "", 0, 0, 0)
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index 8d24e50..e01a04c 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -67,8 +67,9 @@
TYPE("java", Java, INVALID, 0, "u")
// Misc.
-TYPE("llvm-asm", LLVMAsm, INVALID, "s", "")
-TYPE("llvm-bc", LLVMBC, INVALID, "o", "")
+TYPE("ast", AST, INVALID, "ast", "u")
+TYPE("llvm-asm", LLVMAsm, INVALID, "s", "")
+TYPE("llvm-bc", LLVMBC, INVALID, "o", "")
TYPE("plist", Plist, INVALID, "plist", "")
TYPE("precompiled-header", PCH, INVALID, "gch", "A")
TYPE("object", Object, INVALID, "o", "")
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 0280b6e..84e58e8 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -345,11 +345,13 @@
OptionHelp.push_back(std::make_pair("-ccc-gcc-name",
"Name for native GCC compiler"));
OptionHelp.push_back(std::make_pair("-ccc-clang-cxx",
- "Use the clang compiler for C++"));
+ "Enable the clang compiler for C++"));
+ OptionHelp.push_back(std::make_pair("-ccc-no-clang-cxx",
+ "Disable the clang compiler for C++"));
OptionHelp.push_back(std::make_pair("-ccc-no-clang",
- "Never use the clang compiler"));
+ "Disable the clang compiler"));
OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp",
- "Never use the clang preprocessor"));
+ "Disable the clang preprocessor"));
OptionHelp.push_back(std::make_pair("-ccc-clang-archs",
"Comma separate list of architectures "
"to use the clang compiler for"));
@@ -764,10 +766,11 @@
(FinalPhaseArg = Args.getLastArg(options::OPT_MM))) {
FinalPhase = phases::Preprocess;
- // -{fsyntax-only,-analyze,emit-llvm,S} only run up to the compiler.
+ // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT__analyze,
options::OPT__analyze_auto)) ||
+ (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) ||
(FinalPhaseArg = Args.getLastArg(options::OPT_S))) {
FinalPhase = phases::Compile;
@@ -870,6 +873,8 @@
return new CompileJobAction(Input, types::TY_Nothing);
} else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
return new AnalyzeJobAction(Input, types::TY_Plist);
+ } else if (Args.hasArg(options::OPT_emit_ast)) {
+ return new CompileJobAction(Input, types::TY_AST);
} else if (Args.hasArg(options::OPT_emit_llvm) ||
Args.hasArg(options::OPT_flto) ||
Args.hasArg(options::OPT_O4)) {
@@ -1275,7 +1280,7 @@
// Check if user requested no clang, or clang doesn't understand
// this type (we only handle single inputs for now).
- if (!CCCUseClang || JA.size() != 1 ||
+ if (!CCCUseClang || JA.size() != 1 ||
!types::isAcceptedByClang((*JA.begin())->getType()))
return false;
@@ -1294,10 +1299,9 @@
return false;
}
- // Always use clang for precompiling, regardless of archs. PTH is
- // platform independent, and this allows the use of the static
- // analyzer on platforms we don't have full IRgen support for.
- if (isa<PrecompileJobAction>(JA))
+ // Always use clang for precompiling and AST generation, regardless of
+ // archs.
+ if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST)
return true;
// Finally, don't use clang if this isn't one of the user specified
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index efd1917..e93e642 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -220,7 +220,12 @@
} else if (JA.getType() == types::TY_LLVMBC) {
CmdArgs.push_back("-emit-llvm-bc");
} else if (JA.getType() == types::TY_PP_Asm) {
- CmdArgs.push_back("-S");
+ if (Inputs[0].getType() == types::TY_AST)
+ CmdArgs.push_back("-compile-ast");
+ else
+ CmdArgs.push_back("-S");
+ } else if (JA.getType() == types::TY_AST) {
+ CmdArgs.push_back("-emit-pch");
}
}
@@ -768,10 +773,13 @@
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
const InputInfo &II = *it;
- // Don't try to pass LLVM inputs to a generic gcc.
+ // Don't try to pass LLVM or AST inputs to a generic gcc.
if (II.getType() == types::TY_LLVMBC)
D.Diag(clang::diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString().c_str();
+ else if (II.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString().c_str();
if (types::canTypeBeUserSpecified(II.getType())) {
CmdArgs.push_back("-x");
@@ -1189,6 +1197,9 @@
CmdArgs.push_back("-emit-llvm");
else if (Output.getType() == types::TY_LLVMBC)
CmdArgs.push_back("-emit-llvm-bc");
+ else if (Output.getType() == types::TY_AST)
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString().c_str();
ArgStringList OutputArgs;
if (Output.getType() != types::TY_PCH) {
@@ -1224,6 +1235,13 @@
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
const InputInfo &II = *it;
+ // Reject AST inputs.
+ if (II.getType() == types::TY_AST) {
+ D.Diag(clang::diag::err_drv_no_ast_support)
+ << getToolChain().getTripleString().c_str();
+ return;
+ }
+
if (II.isPipe())
CmdArgs.push_back("-");
else
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index e89e973..60248a1 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -83,6 +83,7 @@
case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ case TY_AST:
return true;
}
}
@@ -128,6 +129,7 @@
case 3:
if (memcmp(Ext, "ads", 3) == 0) return TY_Ada;
if (memcmp(Ext, "adb", 3) == 0) return TY_Ada;
+ if (memcmp(Ext, "ast", 3) == 0) return TY_AST;
if (memcmp(Ext, "cxx", 3) == 0) return TY_CXX;
if (memcmp(Ext, "cpp", 3) == 0) return TY_CXX;
if (memcmp(Ext, "CPP", 3) == 0) return TY_CXX;
diff --git a/test/Driver/ast.c b/test/Driver/ast.c
new file mode 100644
index 0000000..b5d342c
--- /dev/null
+++ b/test/Driver/ast.c
@@ -0,0 +1,22 @@
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -emit-ast %s 2> %t &&
+// RUN: FileCheck -check-prefix EMIT-AST-PHASES -input-file %t %s &&
+
+// EMIT-AST-PHASES: 0: input,
+// EMIT-AST-PHASES: , c
+// EMIT-AST-PHASES: 1: preprocessor, {0}, cpp-output
+// EMIT-AST-PHASES: 2: compiler, {1}, ast
+// EMIT-AST-PHASES-NOT: 3:
+
+// RUN: touch %t.ast &&
+// RUN: clang -ccc-host-triple i386-unknown-unknown -ccc-print-phases -c %t.ast 2> %t &&
+// RUN: FileCheck -check-prefix COMPILE-AST-PHASES -input-file %t %s
+
+// COMPILE-AST-PHASES: 0: input,
+// COMPILE-AST-PHASES: , ast
+// COMPILE-AST-PHASES: 1: compiler, {0}, assembler
+// COMPILE-AST-PHASES: 2: assembler, {1}, object
+// COMPILE-AST-PHASES-NOT: 3:
+
+// FIXME: There is a problem with compiling AST's in that the input language is
+// not availabe for use by other tools (for example, to automatically add
+// -lstdc++). We may need -x [objective-]c++-ast and all that goodness. :(