| 1 | //===--- ExecuteCompilerInvocation.cpp ------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file holds ExecuteCompilerInvocation(). It is split into its own file to |
| 10 | // minimize the impact of pulling in essentially everything else in Clang. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "clang/Basic/DiagnosticFrontend.h" |
| 15 | #include "clang/CodeGen/CodeGenAction.h" |
| 16 | #include "clang/Config/config.h" |
| 17 | #include "clang/ExtractAPI/FrontendActions.h" |
| 18 | #include "clang/Frontend/CompilerInstance.h" |
| 19 | #include "clang/Frontend/CompilerInvocation.h" |
| 20 | #include "clang/Frontend/FrontendActions.h" |
| 21 | #include "clang/Frontend/FrontendPluginRegistry.h" |
| 22 | #include "clang/Frontend/SSAFOptions.h" |
| 23 | #include "clang/Frontend/Utils.h" |
| 24 | #include "clang/FrontendTool/Utils.h" |
| 25 | #include "clang/Options/Options.h" |
| 26 | #include "clang/Rewrite/Frontend/FrontendActions.h" |
| 27 | #include "clang/ScalableStaticAnalysis/Frontend/SourceTransformationFrontendAction.h" |
| 28 | #include "clang/ScalableStaticAnalysis/Frontend/TUSummaryExtractorFrontendAction.h" |
| 29 | #include "clang/ScalableStaticAnalysis/SSAFForceLinker.h" // IWYU pragma: keep |
| 30 | #include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" |
| 31 | #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" |
| 32 | #include "llvm/Option/OptTable.h" |
| 33 | #include "llvm/Support/BuryPointer.h" |
| 34 | #include "llvm/Support/DynamicLibrary.h" |
| 35 | #include "llvm/Support/ErrorHandling.h" |
| 36 | |
| 37 | #if CLANG_ENABLE_CIR |
| 38 | #include "mlir/IR/AsmState.h" |
| 39 | #include "mlir/IR/MLIRContext.h" |
| 40 | #include "mlir/Pass/PassManager.h" |
| 41 | #include "clang/CIR/Dialect/Passes.h" |
| 42 | #include "clang/CIR/FrontendAction/CIRGenAction.h" |
| 43 | #endif |
| 44 | |
| 45 | using namespace clang; |
| 46 | using namespace llvm::opt; |
| 47 | |
| 48 | namespace clang { |
| 49 | |
| 50 | static std::unique_ptr<FrontendAction> |
| 51 | CreateFrontendBaseAction(CompilerInstance &CI) { |
| 52 | using namespace clang::frontend; |
| 53 | StringRef Action("unknown" ); |
| 54 | (void)Action; |
| 55 | |
| 56 | unsigned UseCIR = CI.getFrontendOpts().UseClangIRPipeline; |
| 57 | frontend::ActionKind Act = CI.getFrontendOpts().ProgramAction; |
| 58 | bool EmitsCIR = Act == EmitCIR; |
| 59 | |
| 60 | if (!UseCIR && EmitsCIR) |
| 61 | llvm::report_fatal_error(reason: "-emit-cir and only valid when using -fclangir" ); |
| 62 | |
| 63 | switch (CI.getFrontendOpts().ProgramAction) { |
| 64 | case ASTDeclList: return std::make_unique<ASTDeclListAction>(); |
| 65 | case ASTDump: return std::make_unique<ASTDumpAction>(); |
| 66 | case ASTPrint: return std::make_unique<ASTPrintAction>(); |
| 67 | case ASTView: return std::make_unique<ASTViewAction>(); |
| 68 | case DumpCompilerOptions: |
| 69 | return std::make_unique<DumpCompilerOptionsAction>(); |
| 70 | case DumpRawTokens: return std::make_unique<DumpRawTokensAction>(); |
| 71 | case DumpTokens: return std::make_unique<DumpTokensAction>(); |
| 72 | case EmitAssembly: |
| 73 | #if CLANG_ENABLE_CIR |
| 74 | if (UseCIR) |
| 75 | return std::make_unique<cir::EmitAssemblyAction>(); |
| 76 | #endif |
| 77 | return std::make_unique<EmitAssemblyAction>(); |
| 78 | case EmitBC: |
| 79 | #if CLANG_ENABLE_CIR |
| 80 | if (UseCIR) |
| 81 | return std::make_unique<cir::EmitBCAction>(); |
| 82 | #endif |
| 83 | return std::make_unique<EmitBCAction>(); |
| 84 | case EmitCIR: |
| 85 | #if CLANG_ENABLE_CIR |
| 86 | return std::make_unique<cir::EmitCIRAction>(); |
| 87 | #else |
| 88 | CI.getDiagnostics().Report(DiagID: diag::err_fe_cir_not_built); |
| 89 | return nullptr; |
| 90 | #endif |
| 91 | case EmitHTML: return std::make_unique<HTMLPrintAction>(); |
| 92 | case EmitLLVM: { |
| 93 | #if CLANG_ENABLE_CIR |
| 94 | if (UseCIR) |
| 95 | return std::make_unique<cir::EmitLLVMAction>(); |
| 96 | #endif |
| 97 | return std::make_unique<EmitLLVMAction>(); |
| 98 | } |
| 99 | case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>(); |
| 100 | case EmitCodeGenOnly: return std::make_unique<EmitCodeGenOnlyAction>(); |
| 101 | case EmitObj: |
| 102 | #if CLANG_ENABLE_CIR |
| 103 | if (UseCIR) |
| 104 | return std::make_unique<cir::EmitObjAction>(); |
| 105 | #endif |
| 106 | return std::make_unique<EmitObjAction>(); |
| 107 | case ExtractAPI: |
| 108 | return std::make_unique<ExtractAPIAction>(); |
| 109 | case FixIt: return std::make_unique<FixItAction>(); |
| 110 | case GenerateModule: |
| 111 | return std::make_unique<GenerateModuleFromModuleMapAction>(); |
| 112 | case GenerateModuleInterface: |
| 113 | return std::make_unique<GenerateModuleInterfaceAction>(); |
| 114 | case GenerateReducedModuleInterface: |
| 115 | return std::make_unique<GenerateReducedModuleInterfaceAction>(); |
| 116 | case GenerateHeaderUnit: |
| 117 | return std::make_unique<GenerateHeaderUnitAction>(); |
| 118 | case GeneratePCH: return std::make_unique<GeneratePCHAction>(); |
| 119 | case GenerateInterfaceStubs: |
| 120 | return std::make_unique<GenerateInterfaceStubsAction>(); |
| 121 | case InitOnly: return std::make_unique<InitOnlyAction>(); |
| 122 | case ParseSyntaxOnly: return std::make_unique<SyntaxOnlyAction>(); |
| 123 | case ModuleFileInfo: return std::make_unique<DumpModuleInfoAction>(); |
| 124 | case VerifyPCH: |
| 125 | return std::make_unique<VerifyPCHAction>(); |
| 126 | |
| 127 | case PluginAction: { |
| 128 | for (const FrontendPluginRegistry::entry &Plugin : |
| 129 | FrontendPluginRegistry::entries()) { |
| 130 | if (Plugin.getName() == CI.getFrontendOpts().ActionName) { |
| 131 | std::unique_ptr<PluginASTAction> P(Plugin.instantiate()); |
| 132 | if ((P->getActionType() != PluginASTAction::ReplaceAction && |
| 133 | P->getActionType() != PluginASTAction::CmdlineAfterMainAction) || |
| 134 | !P->ParseArgs( |
| 135 | CI, |
| 136 | arg: CI.getFrontendOpts().PluginArgs[std::string(Plugin.getName())])) |
| 137 | return nullptr; |
| 138 | return std::move(P); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | CI.getDiagnostics().Report(DiagID: diag::err_fe_invalid_plugin_name) |
| 143 | << CI.getFrontendOpts().ActionName; |
| 144 | return nullptr; |
| 145 | } |
| 146 | |
| 147 | case PrintPreamble: return std::make_unique<PrintPreambleAction>(); |
| 148 | case PrintPreprocessedInput: { |
| 149 | if (CI.getPreprocessorOutputOpts().RewriteIncludes || |
| 150 | CI.getPreprocessorOutputOpts().RewriteImports) |
| 151 | return std::make_unique<RewriteIncludesAction>(); |
| 152 | return std::make_unique<PrintPreprocessedAction>(); |
| 153 | } |
| 154 | |
| 155 | case RewriteMacros: return std::make_unique<RewriteMacrosAction>(); |
| 156 | case RewriteTest: return std::make_unique<RewriteTestAction>(); |
| 157 | #if CLANG_ENABLE_OBJC_REWRITER |
| 158 | case RewriteObjC: return std::make_unique<RewriteObjCAction>(); |
| 159 | #else |
| 160 | case RewriteObjC: Action = "RewriteObjC" ; break; |
| 161 | #endif |
| 162 | #if CLANG_ENABLE_STATIC_ANALYZER |
| 163 | case RunAnalysis: return std::make_unique<ento::AnalysisAction>(); |
| 164 | #else |
| 165 | case RunAnalysis: Action = "RunAnalysis" ; break; |
| 166 | #endif |
| 167 | case RunPreprocessorOnly: return std::make_unique<PreprocessOnlyAction>(); |
| 168 | case PrintDependencyDirectivesSourceMinimizerOutput: |
| 169 | return std::make_unique<PrintDependencyDirectivesSourceMinimizerAction>(); |
| 170 | } |
| 171 | |
| 172 | #if !CLANG_ENABLE_STATIC_ANALYZER || !CLANG_ENABLE_OBJC_REWRITER |
| 173 | CI.getDiagnostics().Report(DiagID: diag::err_fe_action_not_available) << Action; |
| 174 | return 0; |
| 175 | #else |
| 176 | llvm_unreachable("Invalid program action!" ); |
| 177 | #endif |
| 178 | } |
| 179 | |
| 180 | std::unique_ptr<FrontendAction> |
| 181 | CreateFrontendAction(CompilerInstance &CI) { |
| 182 | // Create the underlying action. |
| 183 | std::unique_ptr<FrontendAction> Act = CreateFrontendBaseAction(CI); |
| 184 | if (!Act) |
| 185 | return nullptr; |
| 186 | |
| 187 | const FrontendOptions &FEOpts = CI.getFrontendOpts(); |
| 188 | |
| 189 | if (CI.getLangOpts().HLSL) |
| 190 | Act = std::make_unique<HLSLFrontendAction>(args: std::move(Act)); |
| 191 | |
| 192 | if (FEOpts.FixAndRecompile) { |
| 193 | Act = std::make_unique<FixItRecompile>(args: std::move(Act)); |
| 194 | } |
| 195 | |
| 196 | // Wrap the base FE action in an extract api action to generate |
| 197 | // symbol graph as a biproduct of compilation (enabled with |
| 198 | // --emit-symbol-graph option) |
| 199 | if (FEOpts.EmitSymbolGraph) { |
| 200 | if (FEOpts.SymbolGraphOutputDir.empty()) { |
| 201 | CI.getDiagnostics().Report(DiagID: diag::warn_missing_symbol_graph_dir); |
| 202 | CI.getFrontendOpts().SymbolGraphOutputDir = "." ; |
| 203 | } |
| 204 | CI.getCodeGenOpts().ClearASTBeforeBackend = false; |
| 205 | Act = std::make_unique<WrappingExtractAPIAction>(args: std::move(Act)); |
| 206 | } |
| 207 | |
| 208 | // If there are any AST files to merge, create a frontend action |
| 209 | // adaptor to perform the merge. |
| 210 | if (!FEOpts.ASTMergeFiles.empty()) |
| 211 | Act = std::make_unique<ASTMergeAction>(args: std::move(Act), |
| 212 | args: FEOpts.ASTMergeFiles); |
| 213 | |
| 214 | if (!CI.getSSAFOpts().TUSummaryFile.empty()) { |
| 215 | Act = std::make_unique<ssaf::TUSummaryExtractorFrontendAction>( |
| 216 | args: std::move(Act)); |
| 217 | } |
| 218 | // Enter the source-transformation action when the transformation option is |
| 219 | // set, and also when only an output option (--ssaf-src-edit-file= / |
| 220 | // --ssaf-transformation-report-file=) is set — the action's |
| 221 | // reportOrphanOptionMisuse then diagnoses that as a reverse orphan rather |
| 222 | // than silently ignoring the option. |
| 223 | if (!CI.getSSAFOpts().SourceTransformation.empty() || |
| 224 | !CI.getSSAFOpts().SrcEditFile.empty() || |
| 225 | !CI.getSSAFOpts().TransformationReportFile.empty()) { |
| 226 | Act = std::make_unique<ssaf::SourceTransformationFrontendAction>( |
| 227 | args: std::move(Act)); |
| 228 | } |
| 229 | return Act; |
| 230 | } |
| 231 | |
| 232 | bool ExecuteCompilerInvocation(CompilerInstance *Clang) { |
| 233 | unsigned NumErrorsBefore = Clang->getDiagnostics().getNumErrors(); |
| 234 | |
| 235 | // Honor -help. |
| 236 | if (Clang->getFrontendOpts().ShowHelp) { |
| 237 | getDriverOptTable().printHelp( |
| 238 | OS&: llvm::outs(), Usage: "clang -cc1 [options] file..." , |
| 239 | Title: "LLVM 'Clang' Compiler: http://clang.llvm.org" , |
| 240 | /*ShowHidden=*/false, /*ShowAllAliases=*/false, |
| 241 | VisibilityMask: llvm::opt::Visibility(options::CC1Option)); |
| 242 | return true; |
| 243 | } |
| 244 | |
| 245 | // Honor -version. |
| 246 | // |
| 247 | // FIXME: Use a better -version message? |
| 248 | if (Clang->getFrontendOpts().ShowVersion) { |
| 249 | llvm::cl::PrintVersionMessage(); |
| 250 | return true; |
| 251 | } |
| 252 | |
| 253 | Clang->LoadRequestedPlugins(); |
| 254 | |
| 255 | // Honor -mllvm. |
| 256 | // |
| 257 | // FIXME: Remove this, one day. |
| 258 | // This should happen AFTER plugins have been loaded! |
| 259 | if (!Clang->getFrontendOpts().LLVMArgs.empty()) { |
| 260 | unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); |
| 261 | auto Args = std::make_unique<const char*[]>(num: NumArgs + 2); |
| 262 | Args[0] = "clang (LLVM option parsing)" ; |
| 263 | for (unsigned i = 0; i != NumArgs; ++i) |
| 264 | Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str(); |
| 265 | Args[NumArgs + 1] = nullptr; |
| 266 | llvm::cl::ParseCommandLineOptions(argc: NumArgs + 1, argv: Args.get(), /*Overview=*/"" , |
| 267 | /*Errs=*/nullptr, |
| 268 | /*VFS=*/&Clang->getVirtualFileSystem()); |
| 269 | } |
| 270 | |
| 271 | #if CLANG_ENABLE_STATIC_ANALYZER |
| 272 | // These should happen AFTER plugins have been loaded! |
| 273 | |
| 274 | AnalyzerOptions &AnOpts = Clang->getAnalyzerOpts(); |
| 275 | |
| 276 | // Honor -analyzer-checker-help and -analyzer-checker-help-hidden. |
| 277 | if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpAlpha || |
| 278 | AnOpts.ShowCheckerHelpDeveloper) { |
| 279 | ento::printCheckerHelp(OS&: llvm::outs(), CI&: *Clang); |
| 280 | return true; |
| 281 | } |
| 282 | |
| 283 | // Honor -analyzer-checker-option-help. |
| 284 | if (AnOpts.ShowCheckerOptionList || AnOpts.ShowCheckerOptionAlphaList || |
| 285 | AnOpts.ShowCheckerOptionDeveloperList) { |
| 286 | ento::printCheckerConfigList(OS&: llvm::outs(), CI&: *Clang); |
| 287 | return true; |
| 288 | } |
| 289 | |
| 290 | // Honor -analyzer-list-enabled-checkers. |
| 291 | if (AnOpts.ShowEnabledCheckerList) { |
| 292 | ento::printEnabledCheckerList(OS&: llvm::outs(), CI&: *Clang); |
| 293 | return true; |
| 294 | } |
| 295 | |
| 296 | // Honor -analyzer-config-help. |
| 297 | if (AnOpts.ShowConfigOptionsList) { |
| 298 | ento::printAnalyzerConfigList(OS&: llvm::outs()); |
| 299 | return true; |
| 300 | } |
| 301 | #endif |
| 302 | |
| 303 | #if CLANG_ENABLE_CIR |
| 304 | if (!Clang->getFrontendOpts().MLIRArgs.empty()) { |
| 305 | mlir::registerCIRPasses(); |
| 306 | mlir::registerMLIRContextCLOptions(); |
| 307 | mlir::registerPassManagerCLOptions(); |
| 308 | mlir::registerAsmPrinterCLOptions(); |
| 309 | unsigned NumArgs = Clang->getFrontendOpts().MLIRArgs.size(); |
| 310 | auto Args = std::make_unique<const char *[]>(NumArgs + 2); |
| 311 | Args[0] = "clang (MLIR option parsing)" ; |
| 312 | for (unsigned i = 0; i != NumArgs; ++i) |
| 313 | Args[i + 1] = Clang->getFrontendOpts().MLIRArgs[i].c_str(); |
| 314 | Args[NumArgs + 1] = nullptr; |
| 315 | llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), |
| 316 | /*Description=*/"" , /*Errs=*/nullptr, |
| 317 | &Clang->getVirtualFileSystem()); |
| 318 | } |
| 319 | #endif |
| 320 | |
| 321 | // If there were errors in the above, don't do anything else. |
| 322 | // This intentionally ignores errors emitted before this function to |
| 323 | // accommodate lenient callers that decided to make progress despite errors. |
| 324 | if (Clang->getDiagnostics().getNumErrors() != NumErrorsBefore) |
| 325 | return false; |
| 326 | |
| 327 | // Create and execute the frontend action. |
| 328 | std::unique_ptr<FrontendAction> Act(CreateFrontendAction(CI&: *Clang)); |
| 329 | if (!Act) |
| 330 | return false; |
| 331 | bool Success = Clang->ExecuteAction(Act&: *Act); |
| 332 | if (Clang->getFrontendOpts().DisableFree) |
| 333 | llvm::BuryPointer(Ptr: std::move(Act)); |
| 334 | return Success; |
| 335 | } |
| 336 | |
| 337 | } // namespace clang |
| 338 | |