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