diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -18,6 +18,7 @@ #include "clang/Driver/Util.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/StringSaver.h" @@ -250,9 +251,18 @@ // getFinalPhase - Determine which compilation mode we are in and record // which option we used to determine the final phase. + // TODO: Much of what getFinalPhase returns are not actually true compiler + // modes. Fold this functionality into Types::getCompilationPhases and + // handleArguments. phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, llvm::opt::Arg **FinalPhaseArg = nullptr) const; + // handleArguments - All code related to claiming and printing diagnostics + // related to arguments to the driver are done here. + void handleArguments(Compilation &C, llvm::opt::DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions, + llvm::opt::Arg *YcArg, llvm::opt::Arg *YuArg) const; + // Before executing jobs, sets up response files for commands that need them. void setUpResponseFiles(Compilation &C, Command &Cmd); diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -3148,76 +3148,9 @@ }; } // anonymous namespace. -void Driver::BuildActions(Compilation &C, DerivedArgList &Args, - const InputList &Inputs, ActionList &Actions) const { - llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); - - if (!SuppressMissingInputWarning && Inputs.empty()) { - Diag(clang::diag::err_drv_no_input_files); - return; - } - - // Reject -Z* at the top level, these options should never have been exposed - // by gcc. - if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) - Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); - - // Diagnose misuse of /Fo. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) { - StringRef V = A->getValue(); - if (Inputs.size() > 1 && !V.empty() && - !llvm::sys::path::is_separator(V.back())) { - // Check whether /Fo tries to name an output file for multiple inputs. - Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) - << A->getSpelling() << V; - Args.eraseArg(options::OPT__SLASH_Fo); - } - } - - // Diagnose misuse of /Fa. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) { - StringRef V = A->getValue(); - if (Inputs.size() > 1 && !V.empty() && - !llvm::sys::path::is_separator(V.back())) { - // Check whether /Fa tries to name an asm file for multiple inputs. - Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) - << A->getSpelling() << V; - Args.eraseArg(options::OPT__SLASH_Fa); - } - } - - // Diagnose misuse of /o. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_o)) { - if (A->getValue()[0] == '\0') { - // It has to have a value. - Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; - Args.eraseArg(options::OPT__SLASH_o); - } - } - - // Ignore /Yc/Yu if both /Yc and /Yu passed but with different filenames. - Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); - Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); - if (YcArg && YuArg && strcmp(YcArg->getValue(), YuArg->getValue()) != 0) { - Diag(clang::diag::warn_drv_ycyu_different_arg_clang_cl); - Args.eraseArg(options::OPT__SLASH_Yc); - Args.eraseArg(options::OPT__SLASH_Yu); - YcArg = YuArg = nullptr; - } - if (YcArg && Inputs.size() > 1) { - Diag(clang::diag::warn_drv_yc_multiple_inputs_clang_cl); - Args.eraseArg(options::OPT__SLASH_Yc); - YcArg = nullptr; - } - - // Builder to be used to build offloading actions. - OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); - - // Construct the actions to perform. - HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; - ActionList LinkerInputs; - - { +void Driver::handleArguments(Compilation &C, DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions, + Arg *YcArg, Arg *YuArg) const { Arg *FinalPhaseArg; phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); @@ -3229,8 +3162,7 @@ Diag(clang::diag::err_drv_lto_without_lld); } - if (FinalPhase == phases::Preprocess || - Args.hasArg(options::OPT__SLASH_Y_)) { + if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) { // If only preprocessing or /Y- is used, all pch handling is disabled. // Rather than check for it everywhere, just remove clang-cl pch-related // flags here. @@ -3317,6 +3249,77 @@ } } +void Driver::BuildActions(Compilation &C, DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions) const { + llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); + + if (!SuppressMissingInputWarning && Inputs.empty()) { + Diag(clang::diag::err_drv_no_input_files); + return; + } + + // Reject -Z* at the top level, these options should never have been exposed + // by gcc. + if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) + Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); + + // Diagnose misuse of /Fo. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) { + StringRef V = A->getValue(); + if (Inputs.size() > 1 && !V.empty() && + !llvm::sys::path::is_separator(V.back())) { + // Check whether /Fo tries to name an output file for multiple inputs. + Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) + << A->getSpelling() << V; + Args.eraseArg(options::OPT__SLASH_Fo); + } + } + + // Diagnose misuse of /Fa. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) { + StringRef V = A->getValue(); + if (Inputs.size() > 1 && !V.empty() && + !llvm::sys::path::is_separator(V.back())) { + // Check whether /Fa tries to name an asm file for multiple inputs. + Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources) + << A->getSpelling() << V; + Args.eraseArg(options::OPT__SLASH_Fa); + } + } + + // Diagnose misuse of /o. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_o)) { + if (A->getValue()[0] == '\0') { + // It has to have a value. + Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1; + Args.eraseArg(options::OPT__SLASH_o); + } + } + + // Ignore /Yc/Yu if both /Yc and /Yu passed but with different filenames. + Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); + Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); + if (YcArg && YuArg && strcmp(YcArg->getValue(), YuArg->getValue()) != 0) { + Diag(clang::diag::warn_drv_ycyu_different_arg_clang_cl); + Args.eraseArg(options::OPT__SLASH_Yc); + Args.eraseArg(options::OPT__SLASH_Yu); + YcArg = YuArg = nullptr; + } + if (YcArg && Inputs.size() > 1) { + Diag(clang::diag::warn_drv_yc_multiple_inputs_clang_cl); + Args.eraseArg(options::OPT__SLASH_Yc); + YcArg = nullptr; + } + + // Builder to be used to build offloading actions. + OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); + + // Construct the actions to perform. + HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; + ActionList LinkerInputs; + + handleArguments(C, Args, Inputs, Actions, YcArg, YuArg); + for (auto &I : Inputs) { types::ID InputType = I.first; const Arg *InputArg = I.second;