diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h --- a/clang/include/clang/Driver/Types.h +++ b/clang/include/clang/Driver/Types.h @@ -11,12 +11,14 @@ #include "clang/Driver/Phases.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Option/ArgList.h" namespace llvm { class StringRef; } namespace clang { namespace driver { +class Driver; namespace types { enum ID { TY_INVALID, @@ -100,6 +102,9 @@ void getCompilationPhases( ID Id, llvm::SmallVectorImpl &Phases); + void getCompilationPhases(const clang::driver::Driver &Driver, + llvm::opt::DerivedArgList &DAL, ID Id, + llvm::SmallVectorImpl &Phases); /// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given /// C type (used for clang++ emulation of g++ behaviour) 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 @@ -3157,17 +3157,6 @@ return; } - Arg *FinalPhaseArg; - phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); - - if (FinalPhase == phases::Link) { - if (Args.hasArg(options::OPT_emit_llvm)) - Diag(clang::diag::err_drv_emit_llvm_link); - if (IsCLMode() && LTOMode != LTOK_None && - !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld")) - Diag(clang::diag::err_drv_lto_without_lld); - } - // Reject -Z* at the top level, these options should never have been exposed // by gcc. if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) @@ -3220,15 +3209,6 @@ Args.eraseArg(options::OPT__SLASH_Yc); YcArg = nullptr; } - 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. - Args.eraseArg(options::OPT__SLASH_Fp); - Args.eraseArg(options::OPT__SLASH_Yc); - Args.eraseArg(options::OPT__SLASH_Yu); - YcArg = YuArg = nullptr; - } // Builder to be used to build offloading actions. OffloadingActionBuilder OffloadBuilder(C, Args, Inputs); @@ -3237,70 +3217,117 @@ HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; ActionList LinkerInputs; - unsigned LastPLSize = 0; - for (auto &I : Inputs) { - types::ID InputType = I.first; - const Arg *InputArg = I.second; + { + Arg *FinalPhaseArg; + phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg); - llvm::SmallVector PL; - types::getCompilationPhases(InputType, PL); - LastPLSize = PL.size(); - - // If the first step comes after the final phase we are doing as part of - // this compilation, warn the user about it. - phases::ID InitialPhase = PL[0]; - if (InitialPhase > FinalPhase) { - if (InputArg->isClaimed()) - continue; + if (FinalPhase == phases::Link) { + if (Args.hasArg(options::OPT_emit_llvm)) + Diag(clang::diag::err_drv_emit_llvm_link); + if (IsCLMode() && LTOMode != LTOK_None && + !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld")) + Diag(clang::diag::err_drv_lto_without_lld); + } + + 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. + Args.eraseArg(options::OPT__SLASH_Fp); + Args.eraseArg(options::OPT__SLASH_Yc); + Args.eraseArg(options::OPT__SLASH_Yu); + YcArg = YuArg = nullptr; + } + + unsigned LastPLSize = 0; + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; - // Claim here to avoid the more general unused warning. - InputArg->claim(); + llvm::SmallVector PL; + types::getCompilationPhases(InputType, PL); + LastPLSize = PL.size(); + + // If the first step comes after the final phase we are doing as part of + // this compilation, warn the user about it. + phases::ID InitialPhase = PL[0]; + if (InitialPhase > FinalPhase) { + if (InputArg->isClaimed()) + continue; + + // Claim here to avoid the more general unused warning. + InputArg->claim(); + + // Suppress all unused style warnings with -Qunused-arguments + if (Args.hasArg(options::OPT_Qunused_arguments)) + continue; - // Suppress all unused style warnings with -Qunused-arguments - if (Args.hasArg(options::OPT_Qunused_arguments)) + // Special case when final phase determined by binary name, rather than + // by a command-line argument with a corresponding Arg. + if (CCCIsCPP()) + Diag(clang::diag::warn_drv_input_file_unused_by_cpp) + << InputArg->getAsString(Args) << getPhaseName(InitialPhase); + // Special case '-E' warning on a previously preprocessed file to make + // more sense. + else if (InitialPhase == phases::Compile && + (Args.getLastArg(options::OPT__SLASH_EP, + options::OPT__SLASH_P) || + Args.getLastArg(options::OPT_E) || + Args.getLastArg(options::OPT_M, options::OPT_MM)) && + getPreprocessedType(InputType) == types::TY_INVALID) + Diag(clang::diag::warn_drv_preprocessed_input_file_unused) + << InputArg->getAsString(Args) << !!FinalPhaseArg + << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); + else + Diag(clang::diag::warn_drv_input_file_unused) + << InputArg->getAsString(Args) << getPhaseName(InitialPhase) + << !!FinalPhaseArg + << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); continue; + } - // Special case when final phase determined by binary name, rather than - // by a command-line argument with a corresponding Arg. - if (CCCIsCPP()) - Diag(clang::diag::warn_drv_input_file_unused_by_cpp) - << InputArg->getAsString(Args) << getPhaseName(InitialPhase); - // Special case '-E' warning on a previously preprocessed file to make - // more sense. - else if (InitialPhase == phases::Compile && - FinalPhase == phases::Preprocess && - getPreprocessedType(InputType) == types::TY_INVALID) - Diag(clang::diag::warn_drv_preprocessed_input_file_unused) - << InputArg->getAsString(Args) << !!FinalPhaseArg - << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); - else - Diag(clang::diag::warn_drv_input_file_unused) - << InputArg->getAsString(Args) << getPhaseName(InitialPhase) - << !!FinalPhaseArg - << (FinalPhaseArg ? FinalPhaseArg->getOption().getName() : ""); - continue; + if (YcArg) { + // Add a separate precompile phase for the compile phase. + if (FinalPhase >= phases::Compile) { + const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); + llvm::SmallVector PCHPL; + types::getCompilationPhases(HeaderType, PCHPL); + // Build the pipeline for the pch file. + Action *ClangClPch = C.MakeAction(*InputArg, HeaderType); + for (phases::ID Phase : PCHPL) + ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); + assert(ClangClPch); + Actions.push_back(ClangClPch); + // The driver currently exits after the first failed command. This + // relies on that behavior, to make sure if the pch generation fails, + // the main compilation won't run. + // FIXME: If the main compilation fails, the PCH generation should + // probably not be considered successful either. + } + } } - if (YcArg) { - // Add a separate precompile phase for the compile phase. - if (FinalPhase >= phases::Compile) { - const types::ID HeaderType = lookupHeaderTypeForSourceType(InputType); - llvm::SmallVector PCHPL; - types::getCompilationPhases(HeaderType, PCHPL); - // Build the pipeline for the pch file. - Action *ClangClPch = - C.MakeAction(*InputArg, HeaderType); - for (phases::ID Phase : PCHPL) - ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch); - assert(ClangClPch); - Actions.push_back(ClangClPch); - // The driver currently exits after the first failed command. This - // relies on that behavior, to make sure if the pch generation fails, - // the main compilation won't run. - // FIXME: If the main compilation fails, the PCH generation should - // probably not be considered successful either. - } + // If we are linking, claim any options which are obviously only used for + // compilation. + // FIXME: Understand why the last Phase List length is used here. + if (FinalPhase == phases::Link && LastPLSize == 1) { + Args.ClaimAllArgs(options::OPT_CompileOnly_Group); + Args.ClaimAllArgs(options::OPT_cl_compile_Group); } + } + + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; + + llvm::SmallVector PL; + types::getCompilationPhases(*this, Args, InputType, PL); + if (!PL.size()) + continue; + + llvm::SmallVector FullPL; + types::getCompilationPhases(InputType, FullPL); // Build the pipeline for this file. Action *Current = C.MakeAction(*InputArg, InputType); @@ -3312,13 +3339,9 @@ for (phases::ID Phase : PL) { - // We are done if this step is past what the user requested. - if (Phase > FinalPhase) - break; - // Add any offload action the host action depends on. Current = OffloadBuilder.addDeviceDependencesToHostAction( - Current, InputArg, Phase, FinalPhase, PL); + Current, InputArg, Phase, PL.back(), FullPL); if (!Current) break; @@ -3379,14 +3402,6 @@ Actions.push_back(LA); } - // If we are linking, claim any options which are obviously only used for - // compilation. - // FIXME: Understand why the last Phase List length is used here. - if (FinalPhase == phases::Link && LastPLSize == 1) { - Args.ClaimAllArgs(options::OPT_CompileOnly_Group); - Args.ClaimAllArgs(options::OPT_cl_compile_Group); - } - // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom // Compile phase that prints out supported cpu models and quits. if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -6,10 +6,14 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Types.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Option/Arg.h" #include #include @@ -293,6 +297,60 @@ assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list"); } +void types::getCompilationPhases(const clang::driver::Driver &Driver, + llvm::opt::DerivedArgList &DAL, ID Id, + llvm::SmallVectorImpl &P) { + llvm::SmallVector PhaseList; + types::getCompilationPhases(InputType, PL); + + if (Driver->CCCIsCPP() || DAL.getLastArg(options::OPT_E) || + DAL.getLastArg(options::OPT__SLASH_EP) || + DAL.getLastArg(options::OPT_M, options::OPT_MM) || + DAL.getLastArg(options::OPT__SLASH_P)) { + // Filter to compiler mode. When the compiler is run as a preprocessor then + // compilation is not an option. + // -S runs the compiler in Assembly listing mode. + for (auto Phase : PhaseList) + if (Phase <= phases::Preprocess) + P.push_back(Phase); + } else if (DAL.getLastArg(options::OPT__precompile)) { + // --precompile only runs up to precompilation. + // This is a clang extension and is not compatible with GCC. + for (auto Phase : PhaseList) + if (Phase <= phases::Precompile) + P.push_back(Phase); + } else if (DAL.getLastArg(options::OPT_fsyntax_only) || + DAL.getLastArg(options::OPT_print_supported_cpus) || + DAL.getLastArg(options::OPT_module_file_info) || + DAL.getLastArg(options::OPT_verify_pch) || + DAL.getLastArg(options::OPT_rewrite_objc) || + DAL.getLastArg(options::OPT_rewrite_legacy_objc) || + DAL.getLastArg(options::OPT__migrate) || + DAL.getLastArg(options::OPT_emit_iterface_stubs) || + DAL.getLastArg(options::OPT__analyze, + options::OPT__analyze_auto) || + DAL.getLastArg(options::OPT_emit_ast)) { + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. + for (auto Phase : PhaseList) + if (Phase <= phases::Compile) + P.push_back(Phase); + } else if (DAL.getLastArg(options::OPT_S) || + DAL.getLastArg(options::OPT_emit_llvm)) { + for (auto Phase : PhaseList) + if (Phase <= phases::Backend) + P.push_back(Phase); + } else if (DAL.getLastArg(options::OPT_c)) { + for (auto Phase : PhaseList) + if (Phase <= phases::Assemble) + P.push_back(Phase); + } else { + // Generally means, do every phase until Link. + for (auto Phase : PhaseList) + P.push_back(Phase); + } + llvm_unreachable("getCompilationPhases(): Reached end of function.") +} + ID types::lookupCXXTypeForCType(ID Id) { switch (Id) { default: