1//===--- FrontendActions.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#include "clang/Frontend/FrontendActions.h"
10#include "clang/AST/ASTConsumer.h"
11#include "clang/AST/Decl.h"
12#include "clang/Basic/DiagnosticFrontend.h"
13#include "clang/Basic/FileManager.h"
14#include "clang/Basic/LangStandard.h"
15#include "clang/Basic/Module.h"
16#include "clang/Basic/TargetInfo.h"
17#include "clang/Frontend/ASTConsumers.h"
18#include "clang/Frontend/ASTUnit.h"
19#include "clang/Frontend/CompilerInstance.h"
20#include "clang/Frontend/MultiplexConsumer.h"
21#include "clang/Frontend/Utils.h"
22#include "clang/Lex/DependencyDirectivesScanner.h"
23#include "clang/Lex/HeaderSearch.h"
24#include "clang/Lex/Preprocessor.h"
25#include "clang/Lex/PreprocessorOptions.h"
26#include "clang/Parse/ParseHLSLRootSignature.h"
27#include "clang/Serialization/ASTReader.h"
28#include "clang/Serialization/ASTWriter.h"
29#include "clang/Serialization/ModuleFile.h"
30#include "llvm/Config/llvm-config.h" // for LLVM_HOST_TRIPLE
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/FileSystem.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/YAMLTraits.h"
35#include "llvm/Support/raw_ostream.h"
36#include <memory>
37#include <optional>
38#include <system_error>
39
40using namespace clang;
41
42//===----------------------------------------------------------------------===//
43// Custom Actions
44//===----------------------------------------------------------------------===//
45
46std::unique_ptr<ASTConsumer>
47InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
48 return std::make_unique<ASTConsumer>();
49}
50
51void InitOnlyAction::ExecuteAction() {
52}
53
54// Basically PreprocessOnlyAction::ExecuteAction.
55void ReadPCHAndPreprocessAction::ExecuteAction() {
56 Preprocessor &PP = getCompilerInstance().getPreprocessor();
57
58 // Ignore unknown pragmas.
59 PP.IgnorePragmas();
60
61 Token Tok;
62 // Start parsing the specified input file.
63 PP.EnterMainSourceFile();
64 do {
65 PP.Lex(Result&: Tok);
66 } while (Tok.isNot(K: tok::eof));
67}
68
69std::unique_ptr<ASTConsumer>
70ReadPCHAndPreprocessAction::CreateASTConsumer(CompilerInstance &CI,
71 StringRef InFile) {
72 return std::make_unique<ASTConsumer>();
73}
74
75//===----------------------------------------------------------------------===//
76// AST Consumer Actions
77//===----------------------------------------------------------------------===//
78
79std::unique_ptr<ASTConsumer>
80ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
81 if (std::unique_ptr<raw_ostream> OS =
82 CI.createDefaultOutputFile(Binary: false, BaseInput: InFile))
83 return CreateASTPrinter(OS: std::move(OS), FilterString: CI.getFrontendOpts().ASTDumpFilter);
84 return nullptr;
85}
86
87std::unique_ptr<ASTConsumer>
88ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
89 // Dumping the AST shows documentation comments.
90 CI.getLangOpts().CommentOpts.RetainComments = true;
91 const FrontendOptions &Opts = CI.getFrontendOpts();
92 return CreateASTDumper(OS: nullptr /*Dump to stdout.*/, FilterString: Opts.ASTDumpFilter,
93 FilterPath: Opts.ASTDumpFilterPath, DumpDecls: Opts.ASTDumpDecls,
94 Deserialize: Opts.ASTDumpAll, DumpLookups: Opts.ASTDumpLookups,
95 DumpDeclTypes: Opts.ASTDumpDeclTypes, Format: Opts.ASTDumpFormat);
96}
97
98std::unique_ptr<ASTConsumer>
99ASTDeclListAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
100 return CreateASTDeclNodeLister();
101}
102
103std::unique_ptr<ASTConsumer>
104ASTViewAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
105 return CreateASTViewer();
106}
107
108std::unique_ptr<ASTConsumer>
109GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
110 std::string Sysroot;
111 if (!ComputeASTConsumerArguments(CI, /*ref*/ Sysroot))
112 return nullptr;
113
114 std::string OutputFile;
115 std::unique_ptr<raw_pwrite_stream> OS =
116 CreateOutputFile(CI, InFile, /*ref*/ OutputFile, SetOnlyIfDifferent);
117 if (!OS)
118 return nullptr;
119
120 if (!CI.getFrontendOpts().RelocatablePCH)
121 Sysroot.clear();
122
123 const auto &FrontendOpts = CI.getFrontendOpts();
124 auto Buffer = std::make_shared<PCHBuffer>();
125 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
126 Consumers.push_back(x: std::make_unique<PCHGenerator>(
127 args&: CI.getPreprocessor(), args&: CI.getModuleCache(), args&: OutputFile, args&: Sysroot, args&: Buffer,
128 args&: CI.getCodeGenOpts(), args: FrontendOpts.ModuleFileExtensions,
129 args&: CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
130 args: FrontendOpts.IncludeTimestamps, args: FrontendOpts.BuildingImplicitModule));
131 Consumers.push_back(x: CI.getPCHContainerWriter().CreatePCHContainerGenerator(
132 CI, MainFileName: std::string(InFile), OutputFileName: OutputFile, OS: std::move(OS), Buffer));
133
134 return std::make_unique<MultiplexConsumer>(args: std::move(Consumers));
135}
136
137bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
138 std::string &Sysroot) {
139 Sysroot = CI.getHeaderSearchOpts().Sysroot;
140 if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) {
141 CI.getDiagnostics().Report(DiagID: diag::err_relocatable_without_isysroot);
142 return false;
143 }
144
145 return true;
146}
147
148std::unique_ptr<llvm::raw_pwrite_stream>
149GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile,
150 std::string &OutputFile,
151 bool SetOnlyIfDifferent) {
152 // Because this is exposed via libclang we must disable RemoveFileOnSignal.
153 std::unique_ptr<raw_pwrite_stream> OS = CI.createDefaultOutputFile(
154 /*Binary=*/true, BaseInput: InFile, /*Extension=*/"", /*RemoveFileOnSignal=*/false,
155 /*CreateMissingDirectories=*/false, /*ForceUseTemporary=*/false,
156 SetOnlyIfDifferent);
157 if (!OS)
158 return nullptr;
159
160 OutputFile = CI.getFrontendOpts().OutputFile;
161 return OS;
162}
163
164bool GeneratePCHAction::shouldEraseOutputFiles() {
165 if (getCompilerInstance().getPreprocessorOpts().AllowPCHWithCompilerErrors)
166 return false;
167 return ASTFrontendAction::shouldEraseOutputFiles();
168}
169
170bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
171 CI.getLangOpts().CompilingPCH = true;
172 return ASTFrontendAction::BeginSourceFileAction(CI);
173}
174
175std::vector<std::unique_ptr<ASTConsumer>>
176GenerateModuleAction::CreateMultiplexConsumer(CompilerInstance &CI,
177 StringRef InFile) {
178 if (!OS)
179 OS = CreateOutputFile(CI, InFile);
180 if (!OS)
181 return {};
182
183 std::string OutputFile = CI.getFrontendOpts().OutputFile;
184 std::string Sysroot;
185
186 auto Buffer = std::make_shared<PCHBuffer>();
187 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
188
189 Consumers.push_back(x: std::make_unique<PCHGenerator>(
190 args&: CI.getPreprocessor(), args&: CI.getModuleCache(), args&: OutputFile, args&: Sysroot, args&: Buffer,
191 args&: CI.getCodeGenOpts(), args&: CI.getFrontendOpts().ModuleFileExtensions,
192 /*AllowASTWithErrors=*/
193 args: +CI.getFrontendOpts().AllowPCMWithCompilerErrors,
194 /*IncludeTimestamps=*/
195 args: +CI.getFrontendOpts().BuildingImplicitModule &&
196 +CI.getFrontendOpts().IncludeTimestamps,
197 /*BuildingImplicitModule=*/args: +CI.getFrontendOpts().BuildingImplicitModule));
198 Consumers.push_back(x: CI.getPCHContainerWriter().CreatePCHContainerGenerator(
199 CI, MainFileName: std::string(InFile), OutputFileName: OutputFile, OS: std::move(OS), Buffer));
200 return Consumers;
201}
202
203std::unique_ptr<ASTConsumer>
204GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
205 StringRef InFile) {
206 std::vector<std::unique_ptr<ASTConsumer>> Consumers =
207 CreateMultiplexConsumer(CI, InFile);
208 if (Consumers.empty())
209 return nullptr;
210
211 return std::make_unique<MultiplexConsumer>(args: std::move(Consumers));
212}
213
214bool GenerateModuleAction::shouldEraseOutputFiles() {
215 return !getCompilerInstance().getFrontendOpts().AllowPCMWithCompilerErrors &&
216 ASTFrontendAction::shouldEraseOutputFiles();
217}
218
219bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
220 CompilerInstance &CI) {
221 if (!CI.getLangOpts().Modules) {
222 CI.getDiagnostics().Report(DiagID: diag::err_module_build_requires_fmodules);
223 return false;
224 }
225
226 return GenerateModuleAction::BeginSourceFileAction(CI);
227}
228
229std::unique_ptr<raw_pwrite_stream>
230GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI,
231 StringRef InFile) {
232 // If no output file was provided, figure out where this module would go
233 // in the module cache.
234 if (CI.getFrontendOpts().OutputFile.empty()) {
235 StringRef ModuleMapFile = CI.getFrontendOpts().OriginalModuleMap;
236 if (ModuleMapFile.empty())
237 ModuleMapFile = InFile;
238
239 HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
240 ModuleFileName FileName = HS.getCachedModuleFileName(
241 ModuleName: CI.getLangOpts().CurrentModule, ModuleMapPath: ModuleMapFile);
242 CI.getFrontendOpts().OutputFile = FileName.str();
243 }
244
245 // Because this is exposed via libclang we must disable RemoveFileOnSignal.
246 return CI.createDefaultOutputFile(/*Binary=*/true, BaseInput: InFile, /*Extension=*/"",
247 /*RemoveFileOnSignal=*/false,
248 /*CreateMissingDirectories=*/true,
249 /*ForceUseTemporary=*/true,
250 /*SetOnlyIfDifferent=*/SetOnlyIfDifferent);
251}
252
253bool GenerateModuleInterfaceAction::PrepareToExecuteAction(
254 CompilerInstance &CI) {
255 // Documentation comments must still be serialized into the BMI
256 // so importers can query them.
257 CI.getLangOpts().CommentOpts.RetainComments = true;
258
259 for (const auto &FIF : CI.getFrontendOpts().Inputs) {
260 if (const auto InputFormat = FIF.getKind().getFormat();
261 InputFormat != InputKind::Format::Source) {
262 CI.getDiagnostics().Report(
263 DiagID: diag::err_frontend_action_unsupported_input_format)
264 << "module interface compilation" << FIF.getFile() << InputFormat;
265 return false;
266 }
267 }
268 return GenerateModuleAction::PrepareToExecuteAction(CI);
269}
270
271bool GenerateModuleInterfaceAction::BeginSourceFileAction(
272 CompilerInstance &CI) {
273 CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
274
275 return GenerateModuleAction::BeginSourceFileAction(CI);
276}
277
278std::unique_ptr<ASTConsumer>
279GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
280 StringRef InFile) {
281 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
282
283 if (CI.getFrontendOpts().GenReducedBMI &&
284 !CI.getFrontendOpts().ModuleOutputPath.empty()) {
285 Consumers.push_back(x: std::make_unique<ReducedBMIGenerator>(
286 args&: CI.getPreprocessor(), args&: CI.getModuleCache(),
287 args&: CI.getFrontendOpts().ModuleOutputPath, args&: CI.getCodeGenOpts(),
288 args: +CI.getFrontendOpts().AllowPCMWithCompilerErrors));
289 }
290
291 Consumers.push_back(x: std::make_unique<CXX20ModulesGenerator>(
292 args&: CI.getPreprocessor(), args&: CI.getModuleCache(),
293 args&: CI.getFrontendOpts().OutputFile, args&: CI.getCodeGenOpts(),
294 args: +CI.getFrontendOpts().AllowPCMWithCompilerErrors));
295
296 return std::make_unique<MultiplexConsumer>(args: std::move(Consumers));
297}
298
299std::unique_ptr<raw_pwrite_stream>
300GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
301 StringRef InFile) {
302 return CI.createDefaultOutputFile(/*Binary=*/true, BaseInput: InFile, Extension: "pcm");
303}
304
305std::unique_ptr<ASTConsumer>
306GenerateReducedModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
307 StringRef InFile) {
308 return std::make_unique<ReducedBMIGenerator>(
309 args&: CI.getPreprocessor(), args&: CI.getModuleCache(),
310 args&: CI.getFrontendOpts().OutputFile, args&: CI.getCodeGenOpts());
311}
312
313bool GenerateHeaderUnitAction::BeginSourceFileAction(CompilerInstance &CI) {
314 if (!CI.getLangOpts().CPlusPlusModules) {
315 CI.getDiagnostics().Report(DiagID: diag::err_module_interface_requires_cpp_modules);
316 return false;
317 }
318 CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderUnit);
319 return GenerateModuleAction::BeginSourceFileAction(CI);
320}
321
322std::unique_ptr<raw_pwrite_stream>
323GenerateHeaderUnitAction::CreateOutputFile(CompilerInstance &CI,
324 StringRef InFile) {
325 return CI.createDefaultOutputFile(/*Binary=*/true, BaseInput: InFile, Extension: "pcm");
326}
327
328SyntaxOnlyAction::~SyntaxOnlyAction() {
329}
330
331std::unique_ptr<ASTConsumer>
332SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
333 return std::make_unique<ASTConsumer>();
334}
335
336std::unique_ptr<ASTConsumer>
337DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
338 StringRef InFile) {
339 return std::make_unique<ASTConsumer>();
340}
341
342std::unique_ptr<ASTConsumer>
343VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
344 return std::make_unique<ASTConsumer>();
345}
346
347void VerifyPCHAction::ExecuteAction() {
348 CompilerInstance &CI = getCompilerInstance();
349 bool Preamble = CI.getPreprocessorOpts().PrecompiledPreambleBytes.first != 0;
350 const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
351 std::unique_ptr<ASTReader> Reader(new ASTReader(
352 CI.getPreprocessor(), CI.getModuleCache(), &CI.getASTContext(),
353 CI.getPCHContainerReader(), CI.getCodeGenOpts(),
354 CI.getFrontendOpts().ModuleFileExtensions,
355 Sysroot.empty() ? "" : Sysroot.c_str(),
356 DisableValidationForModuleKind::None,
357 /*AllowASTWithCompilerErrors*/ false,
358 /*AllowConfigurationMismatch*/ true,
359 /*ValidateSystemInputs*/ true, /*ForceValidateUserInputs*/ true));
360
361 Reader->ReadAST(FileName: ModuleFileName::makeExplicit(Name: getCurrentFile()),
362 Type: Preamble ? serialization::MK_Preamble : serialization::MK_PCH,
363 ImportLoc: SourceLocation(), ClientLoadCapabilities: ASTReader::ARR_ConfigurationMismatch);
364}
365
366namespace {
367 /// AST reader listener that dumps module information for a module
368 /// file.
369 class DumpModuleInfoListener : public ASTReaderListener {
370 llvm::raw_ostream &Out;
371 FileManager &FileMgr;
372
373 public:
374 DumpModuleInfoListener(llvm::raw_ostream &Out, FileManager &FileMgr)
375 : Out(Out), FileMgr(FileMgr) {}
376
377#define DUMP_BOOLEAN(Value, Text) \
378 Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n"
379
380 bool ReadFullVersionInformation(StringRef FullVersion) override {
381 Out.indent(NumSpaces: 2)
382 << "Generated by "
383 << (FullVersion == getClangFullRepositoryVersion()? "this"
384 : "a different")
385 << " Clang: " << FullVersion << "\n";
386 return ASTReaderListener::ReadFullVersionInformation(FullVersion);
387 }
388
389 void ReadModuleName(StringRef ModuleName) override {
390 Out.indent(NumSpaces: 2) << "Module name: " << ModuleName << "\n";
391 }
392 void ReadModuleMapFile(StringRef ModuleMapPath) override {
393 Out.indent(NumSpaces: 2) << "Module map file: " << ModuleMapPath << "\n";
394 }
395
396 bool ReadLanguageOptions(const LangOptions &LangOpts,
397 StringRef ModuleFilename, bool Complain,
398 bool AllowCompatibleDifferences) override {
399 // FIXME: Replace with C++20 `using enum LangOptions::CompatibilityKind`.
400 using CK = LangOptions::CompatibilityKind;
401
402 Out.indent(NumSpaces: 2) << "Language options:\n";
403#define LANGOPT(Name, Bits, Default, Compatibility, Description) \
404 if constexpr (CK::Compatibility != CK::Benign) \
405 DUMP_BOOLEAN(LangOpts.Name, Description);
406#define ENUM_LANGOPT(Name, Type, Bits, Default, Compatibility, Description) \
407 if constexpr (CK::Compatibility != CK::Benign) \
408 Out.indent(4) << Description << ": " \
409 << static_cast<unsigned>(LangOpts.get##Name()) << "\n";
410#define VALUE_LANGOPT(Name, Bits, Default, Compatibility, Description) \
411 if constexpr (CK::Compatibility != CK::Benign) \
412 Out.indent(4) << Description << ": " << LangOpts.Name << "\n";
413#include "clang/Basic/LangOptions.def"
414
415 if (!LangOpts.ModuleFeatures.empty()) {
416 Out.indent(NumSpaces: 4) << "Module features:\n";
417 for (StringRef Feature : LangOpts.ModuleFeatures)
418 Out.indent(NumSpaces: 6) << Feature << "\n";
419 }
420
421 return false;
422 }
423
424 bool ReadTargetOptions(const TargetOptions &TargetOpts,
425 StringRef ModuleFilename, bool Complain,
426 bool AllowCompatibleDifferences) override {
427 Out.indent(NumSpaces: 2) << "Target options:\n";
428 Out.indent(NumSpaces: 4) << " Triple: " << TargetOpts.Triple << "\n";
429 Out.indent(NumSpaces: 4) << " CPU: " << TargetOpts.CPU << "\n";
430 Out.indent(NumSpaces: 4) << " TuneCPU: " << TargetOpts.TuneCPU << "\n";
431 Out.indent(NumSpaces: 4) << " ABI: " << TargetOpts.ABI << "\n";
432
433 if (!TargetOpts.FeaturesAsWritten.empty()) {
434 Out.indent(NumSpaces: 4) << "Target features:\n";
435 for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size();
436 I != N; ++I) {
437 Out.indent(NumSpaces: 6) << TargetOpts.FeaturesAsWritten[I] << "\n";
438 }
439 }
440
441 return false;
442 }
443
444 bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
445 StringRef ModuleFilename,
446 bool Complain) override {
447 Out.indent(NumSpaces: 2) << "Diagnostic options:\n";
448#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts.Name, #Name);
449#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
450 Out.indent(4) << #Name << ": " \
451 << static_cast<unsigned>(DiagOpts.get##Name()) << "\n";
452#define VALUE_DIAGOPT(Name, Bits, Default) \
453 Out.indent(4) << #Name << ": " << DiagOpts.Name << "\n";
454#include "clang/Basic/DiagnosticOptions.def"
455
456 Out.indent(NumSpaces: 4) << "Diagnostic flags:\n";
457 for (const std::string &Warning : DiagOpts.Warnings)
458 Out.indent(NumSpaces: 6) << "-W" << Warning << "\n";
459 for (const std::string &Remark : DiagOpts.Remarks)
460 Out.indent(NumSpaces: 6) << "-R" << Remark << "\n";
461
462 return false;
463 }
464
465 bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
466 StringRef ModuleFilename,
467 StringRef ContextHash,
468 bool Complain) override {
469 std::string SpecificModuleCachePath = createSpecificModuleCachePath(
470 FileMgr, ModuleCachePath: HSOpts.ModuleCachePath, DisableModuleHash: HSOpts.DisableModuleHash,
471 ContextHash: std::string(ContextHash));
472
473 Out.indent(NumSpaces: 2) << "Header search options:\n";
474 Out.indent(NumSpaces: 4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
475 Out.indent(NumSpaces: 4) << "Resource dir [ -resource-dir=]: '" << HSOpts.ResourceDir << "'\n";
476 Out.indent(NumSpaces: 4) << "Module Cache: '" << SpecificModuleCachePath << "'\n";
477 DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
478 "Use builtin include directories [-nobuiltininc]");
479 DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes,
480 "Use standard system include directories [-nostdinc]");
481 DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes,
482 "Use standard C++ include directories [-nostdinc++]");
483 DUMP_BOOLEAN(HSOpts.UseLibcxx,
484 "Use libc++ (rather than libstdc++) [-stdlib=]");
485 return false;
486 }
487
488 bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
489 bool Complain) override {
490 Out.indent(NumSpaces: 2) << "Header search paths:\n";
491 Out.indent(NumSpaces: 4) << "User entries:\n";
492 for (const auto &Entry : HSOpts.UserEntries)
493 Out.indent(NumSpaces: 6) << Entry.Path << "\n";
494 Out.indent(NumSpaces: 4) << "System header prefixes:\n";
495 for (const auto &Prefix : HSOpts.SystemHeaderPrefixes)
496 Out.indent(NumSpaces: 6) << Prefix.Prefix << "\n";
497 Out.indent(NumSpaces: 4) << "VFS overlay files:\n";
498 for (const auto &Overlay : HSOpts.VFSOverlayFiles)
499 Out.indent(NumSpaces: 6) << Overlay << "\n";
500 return false;
501 }
502
503 bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
504 StringRef ModuleFilename, bool ReadMacros,
505 bool Complain,
506 std::string &SuggestedPredefines) override {
507 Out.indent(NumSpaces: 2) << "Preprocessor options:\n";
508 DUMP_BOOLEAN(PPOpts.UsePredefines,
509 "Uses compiler/target-specific predefines [-undef]");
510 DUMP_BOOLEAN(PPOpts.DetailedRecord,
511 "Uses detailed preprocessing record (for indexing)");
512
513 if (ReadMacros) {
514 Out.indent(NumSpaces: 4) << "Predefined macros:\n";
515 }
516
517 for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
518 I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end();
519 I != IEnd; ++I) {
520 Out.indent(NumSpaces: 6);
521 if (I->second)
522 Out << "-U";
523 else
524 Out << "-D";
525 Out << I->first << "\n";
526 }
527 return false;
528 }
529
530 /// Indicates that a particular module file extension has been read.
531 void readModuleFileExtension(
532 const ModuleFileExtensionMetadata &Metadata) override {
533 Out.indent(NumSpaces: 2) << "Module file extension '"
534 << Metadata.BlockName << "' " << Metadata.MajorVersion
535 << "." << Metadata.MinorVersion;
536 if (!Metadata.UserInfo.empty()) {
537 Out << ": ";
538 Out.write_escaped(Str: Metadata.UserInfo);
539 }
540
541 Out << "\n";
542 }
543
544 /// Tells the \c ASTReaderListener that we want to receive the
545 /// input files of the AST file via \c visitInputFile.
546 bool needsInputFileVisitation() override { return true; }
547
548 /// Tells the \c ASTReaderListener that we want to receive the
549 /// input files of the AST file via \c visitInputFile.
550 bool needsSystemInputFileVisitation() override { return true; }
551
552 /// Indicates that the AST file contains particular input file.
553 ///
554 /// \returns true to continue receiving the next input file, false to stop.
555 bool visitInputFileAsRequested(StringRef FilenameAsRequested,
556 StringRef Filename, bool isSystem,
557 bool isOverridden, time_t StoredTime,
558 bool isExplicitModule) override {
559
560 Out.indent(NumSpaces: 2) << "Input file: " << FilenameAsRequested;
561
562 if (isSystem || isOverridden || isExplicitModule) {
563 Out << " [";
564 if (isSystem) {
565 Out << "System";
566 if (isOverridden || isExplicitModule)
567 Out << ", ";
568 }
569 if (isOverridden) {
570 Out << "Overridden";
571 if (isExplicitModule)
572 Out << ", ";
573 }
574 if (isExplicitModule)
575 Out << "ExplicitModule";
576
577 Out << "]";
578 }
579
580 Out << "\n";
581
582 if (StoredTime > 0)
583 Out.indent(NumSpaces: 4) << "MTime: " << llvm::itostr(X: StoredTime) << "\n";
584
585 return true;
586 }
587
588 /// Returns true if this \c ASTReaderListener wants to receive the
589 /// imports of the AST file via \c visitImport, false otherwise.
590 bool needsImportVisitation() const override { return true; }
591
592 /// If needsImportVisitation returns \c true, this is called for each
593 /// AST file imported by this AST file.
594 void visitImport(StringRef ModuleName, StringRef Filename) override {
595 Out.indent(NumSpaces: 2) << "Imports module '" << ModuleName
596 << "': " << Filename.str() << "\n";
597 }
598#undef DUMP_BOOLEAN
599 };
600}
601
602bool DumpModuleInfoAction::BeginInvocation(CompilerInstance &CI) {
603 // The Object file reader also supports raw ast files and there is no point in
604 // being strict about the module file format in -module-file-info mode.
605 CI.getHeaderSearchOpts().ModuleFormat = "obj";
606 return true;
607}
608
609static StringRef ModuleKindName(Module::ModuleKind MK) {
610 switch (MK) {
611 case Module::ModuleMapModule:
612 return "Module Map Module";
613 case Module::ModuleInterfaceUnit:
614 return "Interface Unit";
615 case Module::ModuleImplementationUnit:
616 return "Implementation Unit";
617 case Module::ModulePartitionInterface:
618 return "Partition Interface";
619 case Module::ModulePartitionImplementation:
620 return "Partition Implementation";
621 case Module::ModuleHeaderUnit:
622 return "Header Unit";
623 case Module::ExplicitGlobalModuleFragment:
624 return "Global Module Fragment";
625 case Module::ImplicitGlobalModuleFragment:
626 return "Implicit Module Fragment";
627 case Module::PrivateModuleFragment:
628 return "Private Module Fragment";
629 }
630 llvm_unreachable("unknown module kind!");
631}
632
633void DumpModuleInfoAction::ExecuteAction() {
634 CompilerInstance &CI = getCompilerInstance();
635
636 // Don't process files of type other than module to avoid crash
637 if (!isCurrentFileAST()) {
638 CI.getDiagnostics().Report(DiagID: diag::err_file_is_not_module)
639 << getCurrentFile();
640 return;
641 }
642
643 // Set up the output file.
644 StringRef OutputFileName = CI.getFrontendOpts().OutputFile;
645 if (!OutputFileName.empty() && OutputFileName != "-") {
646 std::error_code EC;
647 OutputStream.reset(p: new llvm::raw_fd_ostream(
648 OutputFileName.str(), EC, llvm::sys::fs::OF_TextWithCRLF));
649 }
650 llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs();
651
652 Out << "Information for module file '" << getCurrentFile() << "':\n";
653 auto &FileMgr = CI.getFileManager();
654 auto Buffer = FileMgr.getBufferForFile(Filename: getCurrentFile());
655 StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer();
656 bool IsRaw = Magic.starts_with(Prefix: "CPCH");
657 Out << " Module format: " << (IsRaw ? "raw" : "obj") << "\n";
658
659 Preprocessor &PP = CI.getPreprocessor();
660 DumpModuleInfoListener Listener(Out, CI.getFileManager());
661 const HeaderSearchOptions &HSOpts =
662 PP.getHeaderSearchInfo().getHeaderSearchOpts();
663
664 // The FrontendAction::BeginSourceFile () method loads the AST so that much
665 // of the information is already available and modules should have been
666 // loaded.
667
668 const LangOptions &LO = getCurrentASTUnit().getLangOpts();
669 if (LO.CPlusPlusModules && !LO.CurrentModule.empty()) {
670 ASTReader *R = getCurrentASTUnit().getASTReader().get();
671 unsigned SubModuleCount = R->getTotalNumSubmodules();
672 serialization::ModuleFile &MF = R->getModuleManager().getPrimaryModule();
673 Out << " ====== C++20 Module structure ======\n";
674
675 if (MF.ModuleName != LO.CurrentModule)
676 Out << " Mismatched module names : " << MF.ModuleName << " and "
677 << LO.CurrentModule << "\n";
678
679 struct SubModInfo {
680 unsigned Idx;
681 Module *Mod;
682 Module::ModuleKind Kind;
683 std::string &Name;
684 bool Seen;
685 };
686 std::map<std::string, SubModInfo> SubModMap;
687 auto PrintSubMapEntry = [&](std::string Name, Module::ModuleKind Kind) {
688 Out << " " << ModuleKindName(MK: Kind) << " '" << Name << "'";
689 auto I = SubModMap.find(x: Name);
690 if (I == SubModMap.end())
691 Out << " was not found in the sub modules!\n";
692 else {
693 I->second.Seen = true;
694 Out << " is at index #" << I->second.Idx << "\n";
695 }
696 };
697 Module *Primary = nullptr;
698 for (unsigned Idx = 0; Idx <= SubModuleCount; ++Idx) {
699 Module *M = R->getModule(ID: Idx);
700 if (!M)
701 continue;
702 if (M->Name == LO.CurrentModule) {
703 Primary = M;
704 Out << " " << ModuleKindName(MK: M->Kind) << " '" << LO.CurrentModule
705 << "' is the Primary Module at index #" << Idx << "\n";
706 SubModMap.insert(x: {M->Name, {.Idx: Idx, .Mod: M, .Kind: M->Kind, .Name: M->Name, .Seen: true}});
707 } else
708 SubModMap.insert(x: {M->Name, {.Idx: Idx, .Mod: M, .Kind: M->Kind, .Name: M->Name, .Seen: false}});
709 }
710 if (Primary) {
711 if (!Primary->submodules().empty())
712 Out << " Sub Modules:\n";
713 for (Module *MI : Primary->submodules()) {
714 PrintSubMapEntry(MI->Name, MI->Kind);
715 }
716 if (!Primary->Imports.empty())
717 Out << " Imports:\n";
718 for (Module *IMP : Primary->Imports) {
719 PrintSubMapEntry(IMP->Name, IMP->Kind);
720 }
721 if (!Primary->Exports.empty())
722 Out << " Exports:\n";
723 for (unsigned MN = 0, N = Primary->Exports.size(); MN != N; ++MN) {
724 if (Module *M = Primary->Exports[MN].first) {
725 PrintSubMapEntry(M->Name, M->Kind);
726 }
727 }
728 }
729
730 // Emit the macro definitions in the module file so that we can know how
731 // much definitions in the module file quickly.
732 // TODO: Emit the macro definition bodies completely.
733 {
734 std::vector<StringRef> MacroNames;
735 for (const auto &M : R->getPreprocessor().macros()) {
736 if (M.first->isFromAST())
737 MacroNames.push_back(x: M.first->getName());
738 }
739 llvm::sort(C&: MacroNames);
740 if (!MacroNames.empty())
741 Out << " Macro Definitions:\n";
742 for (StringRef Name : MacroNames)
743 Out << " " << Name << "\n";
744 }
745
746 // Now let's print out any modules we did not see as part of the Primary.
747 for (const auto &SM : SubModMap) {
748 if (!SM.second.Seen && SM.second.Mod) {
749 Out << " " << ModuleKindName(MK: SM.second.Kind) << " '" << SM.first
750 << "' at index #" << SM.second.Idx
751 << " has no direct reference in the Primary\n";
752 }
753 }
754 Out << " ====== ======\n";
755 }
756
757 // The reminder of the output is produced from the listener as the AST
758 // FileCcontrolBlock is (re-)parsed.
759 ASTReader::readASTFileControlBlock(
760 Filename: getCurrentFile(), FileMgr, ModCache: CI.getModuleCache(),
761 PCHContainerRdr: CI.getPCHContainerReader(),
762 /*FindModuleFileExtensions=*/true, Listener,
763 ValidateDiagnosticOptions: HSOpts.ModulesValidateDiagnosticOptions);
764}
765
766//===----------------------------------------------------------------------===//
767// Preprocessor Actions
768//===----------------------------------------------------------------------===//
769
770void DumpRawTokensAction::ExecuteAction() {
771 Preprocessor &PP = getCompilerInstance().getPreprocessor();
772 SourceManager &SM = PP.getSourceManager();
773
774 // Start lexing the specified input file.
775 llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID: SM.getMainFileID());
776 Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts());
777 RawLex.SetKeepWhitespaceMode(true);
778
779 Token RawTok;
780 RawLex.LexFromRawLexer(Result&: RawTok);
781 while (RawTok.isNot(K: tok::eof)) {
782 PP.DumpToken(Tok: RawTok, DumpFlags: true);
783 llvm::errs() << "\n";
784 RawLex.LexFromRawLexer(Result&: RawTok);
785 }
786}
787
788void DumpTokensAction::ExecuteAction() {
789 Preprocessor &PP = getCompilerInstance().getPreprocessor();
790 // Start preprocessing the specified input file.
791 Token Tok;
792 PP.EnterMainSourceFile();
793 do {
794 PP.Lex(Result&: Tok);
795 PP.DumpToken(Tok, DumpFlags: true);
796 llvm::errs() << "\n";
797 } while (Tok.isNot(K: tok::eof));
798}
799
800void PreprocessOnlyAction::ExecuteAction() {
801 Preprocessor &PP = getCompilerInstance().getPreprocessor();
802
803 // Ignore unknown pragmas.
804 PP.IgnorePragmas();
805
806 Token Tok;
807 // Start parsing the specified input file.
808 PP.EnterMainSourceFile();
809 do {
810 PP.Lex(Result&: Tok);
811 } while (Tok.isNot(K: tok::eof));
812}
813
814void PrintPreprocessedAction::ExecuteAction() {
815 CompilerInstance &CI = getCompilerInstance();
816 // Output file may need to be set to 'Binary', to avoid converting Unix style
817 // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>) on Windows.
818 //
819 // Look to see what type of line endings the file uses. If there's a
820 // CRLF, then we won't open the file up in binary mode. If there is
821 // just an LF or CR, then we will open the file up in binary mode.
822 // In this fashion, the output format should match the input format, unless
823 // the input format has inconsistent line endings.
824 //
825 // This should be a relatively fast operation since most files won't have
826 // all of their source code on a single line. However, that is still a
827 // concern, so if we scan for too long, we'll just assume the file should
828 // be opened in binary mode.
829
830 bool BinaryMode = false;
831 if (llvm::Triple(LLVM_HOST_TRIPLE).isOSWindows()) {
832 BinaryMode = true;
833 const SourceManager &SM = CI.getSourceManager();
834 if (std::optional<llvm::MemoryBufferRef> Buffer =
835 SM.getBufferOrNone(FID: SM.getMainFileID())) {
836 const char *cur = Buffer->getBufferStart();
837 const char *end = Buffer->getBufferEnd();
838 const char *next = (cur != end) ? cur + 1 : end;
839
840 // Limit ourselves to only scanning 256 characters into the source
841 // file. This is mostly a check in case the file has no
842 // newlines whatsoever.
843 if (end - cur > 256)
844 end = cur + 256;
845
846 while (next < end) {
847 if (*cur == 0x0D) { // CR
848 if (*next == 0x0A) // CRLF
849 BinaryMode = false;
850
851 break;
852 } else if (*cur == 0x0A) // LF
853 break;
854
855 ++cur;
856 ++next;
857 }
858 }
859 }
860
861 std::unique_ptr<raw_ostream> OS =
862 CI.createDefaultOutputFile(Binary: BinaryMode, BaseInput: getCurrentFileOrBufferName());
863 if (!OS) return;
864
865 // If we're preprocessing a module map, start by dumping the contents of the
866 // module itself before switching to the input buffer.
867 auto &Input = getCurrentInput();
868 if (Input.getKind().getFormat() == InputKind::ModuleMap) {
869 if (Input.isFile()) {
870 (*OS) << "# 1 \"";
871 OS->write_escaped(Str: Input.getFile());
872 (*OS) << "\"\n";
873 }
874 getCurrentModule()->print(OS&: *OS);
875 (*OS) << "#pragma clang module contents\n";
876 }
877
878 DoPrintPreprocessedInput(PP&: CI.getPreprocessor(), OS: OS.get(),
879 Opts: CI.getPreprocessorOutputOpts());
880}
881
882void PrintPreambleAction::ExecuteAction() {
883 switch (getCurrentFileKind().getLanguage()) {
884 case Language::C:
885 case Language::CXX:
886 case Language::ObjC:
887 case Language::ObjCXX:
888 case Language::OpenCL:
889 case Language::OpenCLCXX:
890 case Language::CUDA:
891 case Language::HIP:
892 case Language::HLSL:
893 break;
894
895 case Language::Unknown:
896 case Language::Asm:
897 case Language::LLVM_IR:
898 case Language::CIR:
899 // We can't do anything with these.
900 return;
901 }
902
903 // We don't expect to find any #include directives in a preprocessed input.
904 if (getCurrentFileKind().isPreprocessed())
905 return;
906
907 CompilerInstance &CI = getCompilerInstance();
908 auto Buffer = CI.getFileManager().getBufferForFile(Filename: getCurrentFile());
909 if (Buffer) {
910 unsigned Preamble =
911 Lexer::ComputePreamble(Buffer: (*Buffer)->getBuffer(), LangOpts: CI.getLangOpts()).Size;
912 llvm::outs().write(Ptr: (*Buffer)->getBufferStart(), Size: Preamble);
913 }
914}
915
916static void writeCompilerOptionValues(raw_ostream &OS,
917 StringRef CompilerOptionNames,
918 ArrayRef<bool> CompilerOptionValues) {
919 bool FirstValue = true;
920 for (bool CompilerOptionValue : CompilerOptionValues) {
921 auto [CompilerOptionName, RemainingCompilerOptionNames] =
922 CompilerOptionNames.split(Separator: '\0');
923 CompilerOptionNames = RemainingCompilerOptionNames;
924 if (!FirstValue)
925 OS << ",\n";
926 FirstValue = false;
927 OS << "\t{\"" << CompilerOptionName
928 << "\" : " << (CompilerOptionValue ? "true" : "false") << "}";
929 }
930 assert(CompilerOptionNames.empty() && "compiler option name count mismatch");
931}
932
933void DumpCompilerOptionsAction::ExecuteAction() {
934 CompilerInstance &CI = getCompilerInstance();
935 std::unique_ptr<raw_ostream> OSP =
936 CI.createDefaultOutputFile(Binary: false, BaseInput: getCurrentFile());
937 if (!OSP)
938 return;
939
940 raw_ostream &OS = *OSP;
941 const Preprocessor &PP = CI.getPreprocessor();
942 const LangOptions &LangOpts = PP.getLangOpts();
943
944 // FIXME: Rather than manually format the JSON (which is awkward due to
945 // needing to remove trailing commas), this should make use of a JSON library.
946 // FIXME: Instead of printing enums as an integral value and specifying the
947 // type as a separate field, use introspection to print the enumerator.
948
949 OS << "{\n";
950 OS << "\n\"features\" : [\n";
951 {
952 static constexpr char FeatureNames[] = {
953#define FEATURE(Name, Predicate) #Name "\0"
954#include "clang/Basic/Features.def"
955 };
956 const bool FeatureValues[] = {
957#define FEATURE(Name, Predicate) static_cast<bool>(Predicate),
958#include "clang/Basic/Features.def"
959 };
960 writeCompilerOptionValues(
961 OS, CompilerOptionNames: StringRef(FeatureNames, sizeof(FeatureNames) - 1), CompilerOptionValues: FeatureValues);
962 }
963 OS << "\n],\n";
964
965 OS << "\n\"extensions\" : [\n";
966 {
967 static constexpr char ExtensionNames[] = {
968#define EXTENSION(Name, Predicate) #Name "\0"
969#include "clang/Basic/Features.def"
970 };
971 const bool ExtensionValues[] = {
972#define EXTENSION(Name, Predicate) static_cast<bool>(Predicate),
973#include "clang/Basic/Features.def"
974 };
975 writeCompilerOptionValues(
976 OS, CompilerOptionNames: StringRef(ExtensionNames, sizeof(ExtensionNames) - 1),
977 CompilerOptionValues: ExtensionValues);
978 }
979 OS << "\n]\n";
980
981 OS << "}";
982}
983
984void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
985 CompilerInstance &CI = getCompilerInstance();
986 SourceManager &SM = CI.getPreprocessor().getSourceManager();
987 llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID: SM.getMainFileID());
988
989 llvm::SmallVector<dependency_directives_scan::Token, 16> Tokens;
990 llvm::SmallVector<dependency_directives_scan::Directive, 32> Directives;
991 if (scanSourceForDependencyDirectives(
992 Input: FromFile.getBuffer(), Tokens, Directives, Diags: &CI.getDiagnostics(),
993 InputSourceLoc: SM.getLocForStartOfFile(FID: SM.getMainFileID()))) {
994 assert(CI.getDiagnostics().hasErrorOccurred() &&
995 "no errors reported for failure");
996
997 // Preprocess the source when verifying the diagnostics to capture the
998 // 'expected' comments.
999 if (CI.getDiagnosticOpts().VerifyDiagnostics) {
1000 // Make sure we don't emit new diagnostics!
1001 CI.getDiagnostics().setSuppressAllDiagnostics(true);
1002 Preprocessor &PP = getCompilerInstance().getPreprocessor();
1003 PP.EnterMainSourceFile();
1004 Token Tok;
1005 do {
1006 PP.Lex(Result&: Tok);
1007 } while (Tok.isNot(K: tok::eof));
1008 }
1009 return;
1010 }
1011 printDependencyDirectivesAsSource(Source: FromFile.getBuffer(), Directives,
1012 OS&: llvm::outs());
1013}
1014
1015//===----------------------------------------------------------------------===//
1016// HLSL Specific Actions
1017//===----------------------------------------------------------------------===//
1018
1019class InjectRootSignatureCallback : public PPCallbacks {
1020private:
1021 Sema &Actions;
1022 StringRef RootSigName;
1023 llvm::dxbc::RootSignatureVersion Version;
1024
1025 std::optional<StringLiteral *> processStringLiteral(ArrayRef<Token> Tokens) {
1026 for (Token Tok : Tokens)
1027 if (!tok::isStringLiteral(K: Tok.getKind()))
1028 return std::nullopt;
1029
1030 ExprResult StringResult = Actions.ActOnUnevaluatedStringLiteral(StringToks: Tokens);
1031 if (StringResult.isInvalid())
1032 return std::nullopt;
1033
1034 if (auto Signature = dyn_cast<StringLiteral>(Val: StringResult.get()))
1035 return Signature;
1036
1037 return std::nullopt;
1038 }
1039
1040public:
1041 void MacroDefined(const Token &MacroNameTok,
1042 const MacroDirective *MD) override {
1043 if (RootSigName != MacroNameTok.getIdentifierInfo()->getName())
1044 return;
1045
1046 const MacroInfo *MI = MD->getMacroInfo();
1047 auto Signature = processStringLiteral(Tokens: MI->tokens());
1048 if (!Signature.has_value()) {
1049 Actions.getDiagnostics().Report(Loc: MI->getDefinitionLoc(),
1050 DiagID: diag::err_expected_string_literal)
1051 << /*in attributes...*/ 4 << "RootSignature";
1052 return;
1053 }
1054
1055 IdentifierInfo *DeclIdent =
1056 hlsl::ParseHLSLRootSignature(Actions, Version, Signature: *Signature);
1057 Actions.HLSL().SetRootSignatureOverride(DeclIdent);
1058 }
1059
1060 InjectRootSignatureCallback(Sema &Actions, StringRef RootSigName,
1061 llvm::dxbc::RootSignatureVersion Version)
1062 : PPCallbacks(), Actions(Actions), RootSigName(RootSigName),
1063 Version(Version) {}
1064};
1065
1066void HLSLFrontendAction::ExecuteAction() {
1067 // Pre-requisites to invoke
1068 CompilerInstance &CI = getCompilerInstance();
1069 if (!CI.hasASTContext() || !CI.hasPreprocessor())
1070 return WrapperFrontendAction::ExecuteAction();
1071
1072 // InjectRootSignatureCallback requires access to invoke Sema to lookup/
1073 // register a root signature declaration. The wrapped action is required to
1074 // account for this by only creating a Sema if one doesn't already exist
1075 // (like we have done, and, ASTFrontendAction::ExecuteAction)
1076 if (!CI.hasSema())
1077 CI.createSema(TUKind: getTranslationUnitKind(),
1078 /*CodeCompleteConsumer=*/CompletionConsumer: nullptr);
1079 Sema &S = CI.getSema();
1080
1081 auto &TargetInfo = CI.getASTContext().getTargetInfo();
1082 bool IsRootSignatureTarget =
1083 TargetInfo.getTriple().getEnvironment() == llvm::Triple::RootSignature;
1084 StringRef HLSLEntry = TargetInfo.getTargetOpts().HLSLEntry;
1085
1086 // Register HLSL specific callbacks
1087 auto LangOpts = CI.getLangOpts();
1088 StringRef RootSigName =
1089 IsRootSignatureTarget ? HLSLEntry : LangOpts.HLSLRootSigOverride;
1090
1091 auto MacroCallback = std::make_unique<InjectRootSignatureCallback>(
1092 args&: S, args&: RootSigName, args&: LangOpts.HLSLRootSigVer);
1093
1094 Preprocessor &PP = CI.getPreprocessor();
1095 PP.addPPCallbacks(C: std::move(MacroCallback));
1096
1097 // If we are targeting a root signature, invoke custom handling
1098 if (IsRootSignatureTarget)
1099 return hlsl::HandleRootSignatureTarget(S, EntryRootSig: HLSLEntry);
1100 else // otherwise, invoke as normal
1101 return WrapperFrontendAction::ExecuteAction();
1102}
1103
1104HLSLFrontendAction::HLSLFrontendAction(
1105 std::unique_ptr<FrontendAction> WrappedAction)
1106 : WrapperFrontendAction(std::move(WrappedAction)) {}
1107