diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index a8dbd68df10f..486bfb3c7e6c 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -43,6 +43,8 @@ def err_drv_invalid_version_number : Error< "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/clang/include/clang/Driver/Options.def b/clang/include/clang/Driver/Options.def index aa10bbfa7a7f..72bc907949d3 100644 --- a/clang/include/clang/Driver/Options.def +++ b/clang/include/clang/Driver/Options.def @@ -353,6 +353,8 @@ OPTION("-dynamiclib", dynamiclib, Flag, INVALID, INVALID, "", 0, 0, 0) 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/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index 8d24e5013fb0..e01a04c67ae1 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -67,8 +67,9 @@ TYPE("f95-cpp-input", Fortran, PP_Fortran, 0, "u") 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/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 0280b6e48209..84e58e8389a3 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -345,11 +345,13 @@ void Driver::PrintHelp(bool ShowHidden) const { 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 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { (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 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, 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 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, // 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 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, 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(JA)) + // Always use clang for precompiling and AST generation, regardless of + // archs. + if (isa(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/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index efd1917f4d7a..e93e6429eb8a 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -220,7 +220,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } 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 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, 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 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, 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 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, 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/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index e89e973f3f53..60248a17c741 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -83,6 +83,7 @@ bool types::isAcceptedByClang(ID Id) { 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 @@ types::ID types::lookupTypeForExtension(const char *Ext) { 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/clang/test/Driver/ast.c b/clang/test/Driver/ast.c new file mode 100644 index 000000000000..b5d342c2665d --- /dev/null +++ b/clang/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. :(