1 //===-- MSVC.cpp - MSVC ToolChain Implementations -------------------------===//
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 "MSVC.h"
10 #include "CommonArgs.h"
11 #include "Darwin.h"
12 #include "clang/Basic/CharInfo.h"
13 #include "clang/Basic/Version.h"
14 #include "clang/Config/config.h"
15 #include "clang/Driver/Compilation.h"
16 #include "clang/Driver/Driver.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "clang/Driver/SanitizerArgs.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/Option/Arg.h"
22 #include "llvm/Option/ArgList.h"
23 #include "llvm/Support/ConvertUTF.h"
24 #include "llvm/Support/ErrorHandling.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/Process.h"
29 #include "llvm/Support/VirtualFileSystem.h"
30 #include "llvm/TargetParser/Host.h"
31 #include <cstdio>
32 
33 #ifdef _WIN32
34   #define WIN32_LEAN_AND_MEAN
35   #define NOGDI
36   #ifndef NOMINMAX
37     #define NOMINMAX
38   #endif
39   #include <windows.h>
40 #endif
41 
42 using namespace clang::driver;
43 using namespace clang::driver::toolchains;
44 using namespace clang::driver::tools;
45 using namespace clang;
46 using namespace llvm::opt;
47 
canExecute(llvm::vfs::FileSystem & VFS,StringRef Path)48 static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) {
49   auto Status = VFS.status(Path);
50   if (!Status)
51     return false;
52   return (Status->getPermissions() & llvm::sys::fs::perms::all_exe) != 0;
53 }
54 
55 // Try to find Exe from a Visual Studio distribution.  This first tries to find
56 // an installed copy of Visual Studio and, failing that, looks in the PATH,
57 // making sure that whatever executable that's found is not a same-named exe
58 // from clang itself to prevent clang from falling back to itself.
FindVisualStudioExecutable(const ToolChain & TC,const char * Exe)59 static std::string FindVisualStudioExecutable(const ToolChain &TC,
60                                               const char *Exe) {
61   const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC);
62   SmallString<128> FilePath(
63       MSVC.getSubDirectoryPath(llvm::SubDirectoryType::Bin));
64   llvm::sys::path::append(FilePath, Exe);
65   return std::string(canExecute(TC.getVFS(), FilePath) ? FilePath.str() : Exe);
66 }
67 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const68 void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
69                                         const InputInfo &Output,
70                                         const InputInfoList &Inputs,
71                                         const ArgList &Args,
72                                         const char *LinkingOutput) const {
73   ArgStringList CmdArgs;
74 
75   auto &TC = static_cast<const toolchains::MSVCToolChain &>(getToolChain());
76 
77   assert((Output.isFilename() || Output.isNothing()) && "invalid output");
78   if (Output.isFilename())
79     CmdArgs.push_back(
80         Args.MakeArgString(std::string("-out:") + Output.getFilename()));
81 
82   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) &&
83       !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) {
84     CmdArgs.push_back("-defaultlib:libcmt");
85     CmdArgs.push_back("-defaultlib:oldnames");
86   }
87 
88   // If the VC environment hasn't been configured (perhaps because the user
89   // did not run vcvarsall), try to build a consistent link environment.  If
90   // the environment variable is set however, assume the user knows what
91   // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that
92   // over env vars.
93   if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir,
94                                      options::OPT__SLASH_winsysroot)) {
95     // cl.exe doesn't find the DIA SDK automatically, so this too requires
96     // explicit flags and doesn't automatically look in "DIA SDK" relative
97     // to the path we found for VCToolChainPath.
98     llvm::SmallString<128> DIAPath(A->getValue());
99     if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
100       llvm::sys::path::append(DIAPath, "DIA SDK");
101 
102     // The DIA SDK always uses the legacy vc arch, even in new MSVC versions.
103     llvm::sys::path::append(DIAPath, "lib",
104                             llvm::archToLegacyVCArch(TC.getArch()));
105     CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath));
106   }
107   if (!llvm::sys::Process::GetEnv("LIB") ||
108       Args.getLastArg(options::OPT__SLASH_vctoolsdir,
109                       options::OPT__SLASH_winsysroot)) {
110     CmdArgs.push_back(Args.MakeArgString(
111         Twine("-libpath:") +
112         TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib)));
113     CmdArgs.push_back(Args.MakeArgString(
114         Twine("-libpath:") +
115         TC.getSubDirectoryPath(llvm::SubDirectoryType::Lib, "atlmfc")));
116   }
117   if (!llvm::sys::Process::GetEnv("LIB") ||
118       Args.getLastArg(options::OPT__SLASH_winsdkdir,
119                       options::OPT__SLASH_winsysroot)) {
120     if (TC.useUniversalCRT()) {
121       std::string UniversalCRTLibPath;
122       if (TC.getUniversalCRTLibraryPath(Args, UniversalCRTLibPath))
123         CmdArgs.push_back(
124             Args.MakeArgString(Twine("-libpath:") + UniversalCRTLibPath));
125     }
126     std::string WindowsSdkLibPath;
127     if (TC.getWindowsSDKLibraryPath(Args, WindowsSdkLibPath))
128       CmdArgs.push_back(
129           Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
130   }
131 
132   if (C.getDriver().IsFlangMode()) {
133     addFortranRuntimeLibraryPath(TC, Args, CmdArgs);
134     addFortranRuntimeLibs(TC, Args, CmdArgs);
135 
136     // Inform the MSVC linker that we're generating a console application, i.e.
137     // one with `main` as the "user-defined" entry point. The `main` function is
138     // defined in flang's runtime libraries.
139     CmdArgs.push_back("/subsystem:console");
140   }
141 
142   // Add the compiler-rt library directories to libpath if they exist to help
143   // the linker find the various sanitizer, builtin, and profiling runtimes.
144   for (const auto &LibPath : TC.getLibraryPaths()) {
145     if (TC.getVFS().exists(LibPath))
146       CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
147   }
148   auto CRTPath = TC.getCompilerRTPath();
149   if (TC.getVFS().exists(CRTPath))
150     CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
151 
152   if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
153     for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
154       CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
155 
156   CmdArgs.push_back("-nologo");
157 
158   if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
159     CmdArgs.push_back("-debug");
160 
161   // If we specify /hotpatch, let the linker add padding in front of each
162   // function, like MSVC does.
163   if (Args.hasArg(options::OPT_fms_hotpatch, options::OPT__SLASH_hotpatch))
164     CmdArgs.push_back("-functionpadmin");
165 
166   // Pass on /Brepro if it was passed to the compiler.
167   // Note that /Brepro maps to -mno-incremental-linker-compatible.
168   bool DefaultIncrementalLinkerCompatible =
169       C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment();
170   if (!Args.hasFlag(options::OPT_mincremental_linker_compatible,
171                     options::OPT_mno_incremental_linker_compatible,
172                     DefaultIncrementalLinkerCompatible))
173     CmdArgs.push_back("-Brepro");
174 
175   bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd,
176                          options::OPT_shared);
177   if (DLL) {
178     CmdArgs.push_back(Args.MakeArgString("-dll"));
179 
180     SmallString<128> ImplibName(Output.getFilename());
181     llvm::sys::path::replace_extension(ImplibName, "lib");
182     CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName));
183   }
184 
185   if (TC.getSanitizerArgs(Args).needsFuzzer()) {
186     if (!Args.hasArg(options::OPT_shared))
187       CmdArgs.push_back(
188           Args.MakeArgString(std::string("-wholearchive:") +
189                              TC.getCompilerRTArgString(Args, "fuzzer")));
190     CmdArgs.push_back(Args.MakeArgString("-debug"));
191     // Prevent the linker from padding sections we use for instrumentation
192     // arrays.
193     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
194   }
195 
196   if (TC.getSanitizerArgs(Args).needsAsanRt()) {
197     CmdArgs.push_back(Args.MakeArgString("-debug"));
198     CmdArgs.push_back(Args.MakeArgString("-incremental:no"));
199     if (TC.getSanitizerArgs(Args).needsSharedRt() ||
200         Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) {
201       for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"})
202         CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
203       // Make sure the dynamic runtime thunk is not optimized out at link time
204       // to ensure proper SEH handling.
205       CmdArgs.push_back(Args.MakeArgString(
206           TC.getArch() == llvm::Triple::x86
207               ? "-include:___asan_seh_interceptor"
208               : "-include:__asan_seh_interceptor"));
209       // Make sure the linker consider all object files from the dynamic runtime
210       // thunk.
211       CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
212           TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk")));
213     } else if (DLL) {
214       CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk"));
215     } else {
216       for (const auto &Lib : {"asan", "asan_cxx"}) {
217         CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib));
218         // Make sure the linker consider all object files from the static lib.
219         // This is necessary because instrumented dlls need access to all the
220         // interface exported by the static lib in the main executable.
221         CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") +
222             TC.getCompilerRT(Args, Lib)));
223       }
224     }
225   }
226 
227   Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link);
228 
229   // Control Flow Guard checks
230   for (const Arg *A : Args.filtered(options::OPT__SLASH_guard)) {
231     StringRef GuardArgs = A->getValue();
232     if (GuardArgs.equals_insensitive("cf") ||
233         GuardArgs.equals_insensitive("cf,nochecks")) {
234       // MSVC doesn't yet support the "nochecks" modifier.
235       CmdArgs.push_back("-guard:cf");
236     } else if (GuardArgs.equals_insensitive("cf-")) {
237       CmdArgs.push_back("-guard:cf-");
238     } else if (GuardArgs.equals_insensitive("ehcont")) {
239       CmdArgs.push_back("-guard:ehcont");
240     } else if (GuardArgs.equals_insensitive("ehcont-")) {
241       CmdArgs.push_back("-guard:ehcont-");
242     }
243   }
244 
245   if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
246                    options::OPT_fno_openmp, false)) {
247     CmdArgs.push_back("-nodefaultlib:vcomp.lib");
248     CmdArgs.push_back("-nodefaultlib:vcompd.lib");
249     CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
250                                          TC.getDriver().Dir + "/../lib"));
251     switch (TC.getDriver().getOpenMPRuntime(Args)) {
252     case Driver::OMPRT_OMP:
253       CmdArgs.push_back("-defaultlib:libomp.lib");
254       break;
255     case Driver::OMPRT_IOMP5:
256       CmdArgs.push_back("-defaultlib:libiomp5md.lib");
257       break;
258     case Driver::OMPRT_GOMP:
259       break;
260     case Driver::OMPRT_Unknown:
261       // Already diagnosed.
262       break;
263     }
264   }
265 
266   // Add compiler-rt lib in case if it was explicitly
267   // specified as an argument for --rtlib option.
268   if (!Args.hasArg(options::OPT_nostdlib)) {
269     AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args);
270   }
271 
272   StringRef Linker =
273       Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
274   if (Linker.empty())
275     Linker = "link";
276   // We need to translate 'lld' into 'lld-link'.
277   else if (Linker.equals_insensitive("lld"))
278     Linker = "lld-link";
279 
280   if (Linker == "lld-link") {
281     for (Arg *A : Args.filtered(options::OPT_vfsoverlay))
282       CmdArgs.push_back(
283           Args.MakeArgString(std::string("/vfsoverlay:") + A->getValue()));
284 
285     if (C.getDriver().isUsingLTO() &&
286         Args.hasFlag(options::OPT_gsplit_dwarf, options::OPT_gno_split_dwarf,
287                      false))
288       CmdArgs.push_back(Args.MakeArgString(Twine("/dwodir:") +
289                                            Output.getFilename() + "_dwo"));
290   }
291 
292   // Add filenames, libraries, and other linker inputs.
293   for (const auto &Input : Inputs) {
294     if (Input.isFilename()) {
295       CmdArgs.push_back(Input.getFilename());
296       continue;
297     }
298 
299     const Arg &A = Input.getInputArg();
300 
301     // Render -l options differently for the MSVC linker.
302     if (A.getOption().matches(options::OPT_l)) {
303       StringRef Lib = A.getValue();
304       const char *LinkLibArg;
305       if (Lib.ends_with(".lib"))
306         LinkLibArg = Args.MakeArgString(Lib);
307       else
308         LinkLibArg = Args.MakeArgString(Lib + ".lib");
309       CmdArgs.push_back(LinkLibArg);
310       continue;
311     }
312 
313     // Otherwise, this is some other kind of linker input option like -Wl, -z,
314     // or -L. Render it, even if MSVC doesn't understand it.
315     A.renderAsInput(Args, CmdArgs);
316   }
317 
318   addHIPRuntimeLibArgs(TC, C, Args, CmdArgs);
319 
320   TC.addProfileRTLibs(Args, CmdArgs);
321 
322   std::vector<const char *> Environment;
323 
324   // We need to special case some linker paths. In the case of the regular msvc
325   // linker, we need to use a special search algorithm.
326   llvm::SmallString<128> linkPath;
327   if (Linker.equals_insensitive("link")) {
328     // If we're using the MSVC linker, it's not sufficient to just use link
329     // from the program PATH, because other environments like GnuWin32 install
330     // their own link.exe which may come first.
331     linkPath = FindVisualStudioExecutable(TC, "link.exe");
332 
333     if (!TC.FoundMSVCInstall() && !canExecute(TC.getVFS(), linkPath)) {
334       llvm::SmallString<128> ClPath;
335       ClPath = TC.GetProgramPath("cl.exe");
336       if (canExecute(TC.getVFS(), ClPath)) {
337         linkPath = llvm::sys::path::parent_path(ClPath);
338         llvm::sys::path::append(linkPath, "link.exe");
339         if (!canExecute(TC.getVFS(), linkPath))
340           C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
341       } else {
342         C.getDriver().Diag(clang::diag::warn_drv_msvc_not_found);
343       }
344     }
345 
346     // Clang handles passing the proper asan libs to the linker, which goes
347     // against link.exe's /INFERASANLIBS which automatically finds asan libs.
348     if (TC.getSanitizerArgs(Args).needsAsanRt())
349       CmdArgs.push_back("/INFERASANLIBS:NO");
350 
351 #ifdef _WIN32
352     // When cross-compiling with VS2017 or newer, link.exe expects to have
353     // its containing bin directory at the top of PATH, followed by the
354     // native target bin directory.
355     // e.g. when compiling for x86 on an x64 host, PATH should start with:
356     // /bin/Hostx64/x86;/bin/Hostx64/x64
357     // This doesn't attempt to handle llvm::ToolsetLayout::DevDivInternal.
358     if (TC.getIsVS2017OrNewer() &&
359         llvm::Triple(llvm::sys::getProcessTriple()).getArch() != TC.getArch()) {
360       auto HostArch = llvm::Triple(llvm::sys::getProcessTriple()).getArch();
361 
362       auto EnvBlockWide =
363           std::unique_ptr<wchar_t[], decltype(&FreeEnvironmentStringsW)>(
364               GetEnvironmentStringsW(), FreeEnvironmentStringsW);
365       if (!EnvBlockWide)
366         goto SkipSettingEnvironment;
367 
368       size_t EnvCount = 0;
369       size_t EnvBlockLen = 0;
370       while (EnvBlockWide[EnvBlockLen] != L'\0') {
371         ++EnvCount;
372         EnvBlockLen += std::wcslen(&EnvBlockWide[EnvBlockLen]) +
373                        1 /*string null-terminator*/;
374       }
375       ++EnvBlockLen; // add the block null-terminator
376 
377       std::string EnvBlock;
378       if (!llvm::convertUTF16ToUTF8String(
379               llvm::ArrayRef<char>(reinterpret_cast<char *>(EnvBlockWide.get()),
380                                    EnvBlockLen * sizeof(EnvBlockWide[0])),
381               EnvBlock))
382         goto SkipSettingEnvironment;
383 
384       Environment.reserve(EnvCount);
385 
386       // Now loop over each string in the block and copy them into the
387       // environment vector, adjusting the PATH variable as needed when we
388       // find it.
389       for (const char *Cursor = EnvBlock.data(); *Cursor != '\0';) {
390         llvm::StringRef EnvVar(Cursor);
391         if (EnvVar.starts_with_insensitive("path=")) {
392           constexpr size_t PrefixLen = 5; // strlen("path=")
393           Environment.push_back(Args.MakeArgString(
394               EnvVar.substr(0, PrefixLen) +
395               TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin) +
396               llvm::Twine(llvm::sys::EnvPathSeparator) +
397               TC.getSubDirectoryPath(llvm::SubDirectoryType::Bin, HostArch) +
398               (EnvVar.size() > PrefixLen
399                    ? llvm::Twine(llvm::sys::EnvPathSeparator) +
400                          EnvVar.substr(PrefixLen)
401                    : "")));
402         } else {
403           Environment.push_back(Args.MakeArgString(EnvVar));
404         }
405         Cursor += EnvVar.size() + 1 /*null-terminator*/;
406       }
407     }
408   SkipSettingEnvironment:;
409 #endif
410   } else {
411     linkPath = TC.GetProgramPath(Linker.str().c_str());
412   }
413 
414   auto LinkCmd = std::make_unique<Command>(
415       JA, *this, ResponseFileSupport::AtFileUTF16(),
416       Args.MakeArgString(linkPath), CmdArgs, Inputs, Output);
417   if (!Environment.empty())
418     LinkCmd->setEnvironment(Environment);
419   C.addCommand(std::move(LinkCmd));
420 }
421 
MSVCToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)422 MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
423                              const ArgList &Args)
424     : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args),
425       RocmInstallation(D, Triple, Args) {
426   getProgramPaths().push_back(getDriver().getInstalledDir());
427   if (getDriver().getInstalledDir() != getDriver().Dir)
428     getProgramPaths().push_back(getDriver().Dir);
429 
430   std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
431   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
432     VCToolsDir = A->getValue();
433   if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
434     VCToolsVersion = A->getValue();
435   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkdir))
436     WinSdkDir = A->getValue();
437   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsdkversion))
438     WinSdkVersion = A->getValue();
439   if (Arg *A = Args.getLastArg(options::OPT__SLASH_winsysroot))
440     WinSysRoot = A->getValue();
441 
442   // Check the command line first, that's the user explicitly telling us what to
443   // use. Check the environment next, in case we're being invoked from a VS
444   // command prompt. Failing that, just try to find the newest Visual Studio
445   // version we can and use its default VC toolchain.
446   llvm::findVCToolChainViaCommandLine(getVFS(), VCToolsDir, VCToolsVersion,
447                                       WinSysRoot, VCToolChainPath, VSLayout) ||
448       llvm::findVCToolChainViaEnvironment(getVFS(), VCToolChainPath,
449                                           VSLayout) ||
450       llvm::findVCToolChainViaSetupConfig(getVFS(), VCToolsVersion,
451                                           VCToolChainPath, VSLayout) ||
452       llvm::findVCToolChainViaRegistry(VCToolChainPath, VSLayout);
453 }
454 
buildLinker() const455 Tool *MSVCToolChain::buildLinker() const {
456   return new tools::visualstudio::Linker(*this);
457 }
458 
buildAssembler() const459 Tool *MSVCToolChain::buildAssembler() const {
460   if (getTriple().isOSBinFormatMachO())
461     return new tools::darwin::Assembler(*this);
462   getDriver().Diag(clang::diag::err_no_external_assembler);
463   return nullptr;
464 }
465 
466 ToolChain::UnwindTableLevel
getDefaultUnwindTableLevel(const ArgList & Args) const467 MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
468   // Don't emit unwind tables by default for MachO targets.
469   if (getTriple().isOSBinFormatMachO())
470     return UnwindTableLevel::None;
471 
472   // All non-x86_32 Windows targets require unwind tables. However, LLVM
473   // doesn't know how to generate them for all targets, so only enable
474   // the ones that are actually implemented.
475   if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
476       getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
477     return UnwindTableLevel::Asynchronous;
478 
479   return UnwindTableLevel::None;
480 }
481 
isPICDefault() const482 bool MSVCToolChain::isPICDefault() const {
483   return getArch() == llvm::Triple::x86_64 ||
484          getArch() == llvm::Triple::aarch64;
485 }
486 
isPIEDefault(const llvm::opt::ArgList & Args) const487 bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const {
488   return false;
489 }
490 
isPICDefaultForced() const491 bool MSVCToolChain::isPICDefaultForced() const {
492   return getArch() == llvm::Triple::x86_64 ||
493          getArch() == llvm::Triple::aarch64;
494 }
495 
AddCudaIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const496 void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
497                                        ArgStringList &CC1Args) const {
498   CudaInstallation->AddCudaIncludeArgs(DriverArgs, CC1Args);
499 }
500 
AddHIPIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const501 void MSVCToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
502                                       ArgStringList &CC1Args) const {
503   RocmInstallation->AddHIPIncludeArgs(DriverArgs, CC1Args);
504 }
505 
AddHIPRuntimeLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const506 void MSVCToolChain::AddHIPRuntimeLibArgs(const ArgList &Args,
507                                          ArgStringList &CmdArgs) const {
508   CmdArgs.append({Args.MakeArgString(StringRef("-libpath:") +
509                                      RocmInstallation->getLibPath()),
510                   "amdhip64.lib"});
511 }
512 
printVerboseInfo(raw_ostream & OS) const513 void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const {
514   CudaInstallation->print(OS);
515   RocmInstallation->print(OS);
516 }
517 
518 std::string
getSubDirectoryPath(llvm::SubDirectoryType Type,llvm::StringRef SubdirParent) const519 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
520                                    llvm::StringRef SubdirParent) const {
521   return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, getArch(),
522                                    SubdirParent);
523 }
524 
525 std::string
getSubDirectoryPath(llvm::SubDirectoryType Type,llvm::Triple::ArchType TargetArch) const526 MSVCToolChain::getSubDirectoryPath(llvm::SubDirectoryType Type,
527                                    llvm::Triple::ArchType TargetArch) const {
528   return llvm::getSubDirectoryPath(Type, VSLayout, VCToolChainPath, TargetArch,
529                                    "");
530 }
531 
532 // Find the most recent version of Universal CRT or Windows 10 SDK.
533 // vcvarsqueryregistry.bat from Visual Studio 2015 sorts entries in the include
534 // directory by name and uses the last one of the list.
535 // So we compare entry names lexicographically to find the greatest one.
536 // Gets the library path required to link against the Windows SDK.
getWindowsSDKLibraryPath(const ArgList & Args,std::string & path) const537 bool MSVCToolChain::getWindowsSDKLibraryPath(const ArgList &Args,
538                                              std::string &path) const {
539   std::string sdkPath;
540   int sdkMajor = 0;
541   std::string windowsSDKIncludeVersion;
542   std::string windowsSDKLibVersion;
543 
544   path.clear();
545   if (!llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
546                               sdkPath, sdkMajor, windowsSDKIncludeVersion,
547                               windowsSDKLibVersion))
548     return false;
549 
550   llvm::SmallString<128> libPath(sdkPath);
551   llvm::sys::path::append(libPath, "Lib");
552   if (sdkMajor >= 10)
553     if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
554         WinSdkVersion.has_value())
555       windowsSDKLibVersion = *WinSdkVersion;
556   if (sdkMajor >= 8)
557     llvm::sys::path::append(libPath, windowsSDKLibVersion, "um");
558   return llvm::appendArchToWindowsSDKLibPath(sdkMajor, libPath, getArch(),
559                                              path);
560 }
561 
useUniversalCRT() const562 bool MSVCToolChain::useUniversalCRT() const {
563   return llvm::useUniversalCRT(VSLayout, VCToolChainPath, getArch(), getVFS());
564 }
565 
getUniversalCRTLibraryPath(const ArgList & Args,std::string & Path) const566 bool MSVCToolChain::getUniversalCRTLibraryPath(const ArgList &Args,
567                                                std::string &Path) const {
568   std::string UniversalCRTSdkPath;
569   std::string UCRTVersion;
570 
571   Path.clear();
572   if (!llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
573                                    WinSysRoot, UniversalCRTSdkPath,
574                                    UCRTVersion))
575     return false;
576 
577   if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
578       WinSdkVersion.has_value())
579     UCRTVersion = *WinSdkVersion;
580 
581   StringRef ArchName = llvm::archToWindowsSDKArch(getArch());
582   if (ArchName.empty())
583     return false;
584 
585   llvm::SmallString<128> LibPath(UniversalCRTSdkPath);
586   llvm::sys::path::append(LibPath, "Lib", UCRTVersion, "ucrt", ArchName);
587 
588   Path = std::string(LibPath);
589   return true;
590 }
591 
getMSVCVersionFromExe(const std::string & BinDir)592 static VersionTuple getMSVCVersionFromExe(const std::string &BinDir) {
593   VersionTuple Version;
594 #ifdef _WIN32
595   SmallString<128> ClExe(BinDir);
596   llvm::sys::path::append(ClExe, "cl.exe");
597 
598   std::wstring ClExeWide;
599   if (!llvm::ConvertUTF8toWide(ClExe.c_str(), ClExeWide))
600     return Version;
601 
602   const DWORD VersionSize = ::GetFileVersionInfoSizeW(ClExeWide.c_str(),
603                                                       nullptr);
604   if (VersionSize == 0)
605     return Version;
606 
607   SmallVector<uint8_t, 4 * 1024> VersionBlock(VersionSize);
608   if (!::GetFileVersionInfoW(ClExeWide.c_str(), 0, VersionSize,
609                              VersionBlock.data()))
610     return Version;
611 
612   VS_FIXEDFILEINFO *FileInfo = nullptr;
613   UINT FileInfoSize = 0;
614   if (!::VerQueryValueW(VersionBlock.data(), L"\\",
615                         reinterpret_cast<LPVOID *>(&FileInfo), &FileInfoSize) ||
616       FileInfoSize < sizeof(*FileInfo))
617     return Version;
618 
619   const unsigned Major = (FileInfo->dwFileVersionMS >> 16) & 0xFFFF;
620   const unsigned Minor = (FileInfo->dwFileVersionMS      ) & 0xFFFF;
621   const unsigned Micro = (FileInfo->dwFileVersionLS >> 16) & 0xFFFF;
622 
623   Version = VersionTuple(Major, Minor, Micro);
624 #endif
625   return Version;
626 }
627 
AddSystemIncludeWithSubfolder(const ArgList & DriverArgs,ArgStringList & CC1Args,const std::string & folder,const Twine & subfolder1,const Twine & subfolder2,const Twine & subfolder3) const628 void MSVCToolChain::AddSystemIncludeWithSubfolder(
629     const ArgList &DriverArgs, ArgStringList &CC1Args,
630     const std::string &folder, const Twine &subfolder1, const Twine &subfolder2,
631     const Twine &subfolder3) const {
632   llvm::SmallString<128> path(folder);
633   llvm::sys::path::append(path, subfolder1, subfolder2, subfolder3);
634   addSystemInclude(DriverArgs, CC1Args, path);
635 }
636 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const637 void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
638                                               ArgStringList &CC1Args) const {
639   if (DriverArgs.hasArg(options::OPT_nostdinc))
640     return;
641 
642   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
643     AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, getDriver().ResourceDir,
644                                   "include");
645   }
646 
647   // Add %INCLUDE%-like directories from the -imsvc flag.
648   for (const auto &Path : DriverArgs.getAllArgValues(options::OPT__SLASH_imsvc))
649     addSystemInclude(DriverArgs, CC1Args, Path);
650 
651   auto AddSystemIncludesFromEnv = [&](StringRef Var) -> bool {
652     if (auto Val = llvm::sys::Process::GetEnv(Var)) {
653       SmallVector<StringRef, 8> Dirs;
654       StringRef(*Val).split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
655       if (!Dirs.empty()) {
656         addSystemIncludes(DriverArgs, CC1Args, Dirs);
657         return true;
658       }
659     }
660     return false;
661   };
662 
663   // Add %INCLUDE%-like dirs via /external:env: flags.
664   for (const auto &Var :
665        DriverArgs.getAllArgValues(options::OPT__SLASH_external_env)) {
666     AddSystemIncludesFromEnv(Var);
667   }
668 
669   // Add DIA SDK include if requested.
670   if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir,
671                                            options::OPT__SLASH_winsysroot)) {
672     // cl.exe doesn't find the DIA SDK automatically, so this too requires
673     // explicit flags and doesn't automatically look in "DIA SDK" relative
674     // to the path we found for VCToolChainPath.
675     llvm::SmallString<128> DIASDKPath(A->getValue());
676     if (A->getOption().getID() == options::OPT__SLASH_winsysroot)
677       llvm::sys::path::append(DIASDKPath, "DIA SDK");
678     AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath),
679                                   "include");
680   }
681 
682   if (DriverArgs.hasArg(options::OPT_nostdlibinc))
683     return;
684 
685   // Honor %INCLUDE% and %EXTERNAL_INCLUDE%. It should have essential search
686   // paths set by vcvarsall.bat. Skip if the user expressly set a vctoolsdir.
687   if (!DriverArgs.getLastArg(options::OPT__SLASH_vctoolsdir,
688                              options::OPT__SLASH_winsysroot)) {
689     bool Found = AddSystemIncludesFromEnv("INCLUDE");
690     Found |= AddSystemIncludesFromEnv("EXTERNAL_INCLUDE");
691     if (Found)
692       return;
693   }
694 
695   // When built with access to the proper Windows APIs, try to actually find
696   // the correct include paths first.
697   if (!VCToolChainPath.empty()) {
698     addSystemInclude(DriverArgs, CC1Args,
699                      getSubDirectoryPath(llvm::SubDirectoryType::Include));
700     addSystemInclude(
701         DriverArgs, CC1Args,
702         getSubDirectoryPath(llvm::SubDirectoryType::Include, "atlmfc"));
703 
704     if (useUniversalCRT()) {
705       std::string UniversalCRTSdkPath;
706       std::string UCRTVersion;
707       if (llvm::getUniversalCRTSdkDir(getVFS(), WinSdkDir, WinSdkVersion,
708                                       WinSysRoot, UniversalCRTSdkPath,
709                                       UCRTVersion)) {
710         if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
711             WinSdkVersion.has_value())
712           UCRTVersion = *WinSdkVersion;
713         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, UniversalCRTSdkPath,
714                                       "Include", UCRTVersion, "ucrt");
715       }
716     }
717 
718     std::string WindowsSDKDir;
719     int major = 0;
720     std::string windowsSDKIncludeVersion;
721     std::string windowsSDKLibVersion;
722     if (llvm::getWindowsSDKDir(getVFS(), WinSdkDir, WinSdkVersion, WinSysRoot,
723                                WindowsSDKDir, major, windowsSDKIncludeVersion,
724                                windowsSDKLibVersion)) {
725       if (major >= 10)
726         if (!(WinSdkDir.has_value() || WinSysRoot.has_value()) &&
727             WinSdkVersion.has_value())
728           windowsSDKIncludeVersion = windowsSDKLibVersion = *WinSdkVersion;
729       if (major >= 8) {
730         // Note: windowsSDKIncludeVersion is empty for SDKs prior to v10.
731         // Anyway, llvm::sys::path::append is able to manage it.
732         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
733                                       "Include", windowsSDKIncludeVersion,
734                                       "shared");
735         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
736                                       "Include", windowsSDKIncludeVersion,
737                                       "um");
738         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
739                                       "Include", windowsSDKIncludeVersion,
740                                       "winrt");
741         if (major >= 10) {
742           llvm::VersionTuple Tuple;
743           if (!Tuple.tryParse(windowsSDKIncludeVersion) &&
744               Tuple.getSubminor().value_or(0) >= 17134) {
745             AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
746                                           "Include", windowsSDKIncludeVersion,
747                                           "cppwinrt");
748           }
749         }
750       } else {
751         AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, WindowsSDKDir,
752                                       "Include");
753       }
754     }
755 
756     return;
757   }
758 
759 #if defined(_WIN32)
760   // As a fallback, select default install paths.
761   // FIXME: Don't guess drives and paths like this on Windows.
762   const StringRef Paths[] = {
763     "C:/Program Files/Microsoft Visual Studio 10.0/VC/include",
764     "C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
765     "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
766     "C:/Program Files/Microsoft Visual Studio 8/VC/include",
767     "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include"
768   };
769   addSystemIncludes(DriverArgs, CC1Args, Paths);
770 #endif
771 }
772 
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const773 void MSVCToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
774                                                  ArgStringList &CC1Args) const {
775   // FIXME: There should probably be logic here to find libc++ on Windows.
776 }
777 
computeMSVCVersion(const Driver * D,const ArgList & Args) const778 VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D,
779                                                const ArgList &Args) const {
780   bool IsWindowsMSVC = getTriple().isWindowsMSVCEnvironment();
781   VersionTuple MSVT = ToolChain::computeMSVCVersion(D, Args);
782   if (MSVT.empty())
783     MSVT = getTriple().getEnvironmentVersion();
784   if (MSVT.empty() && IsWindowsMSVC)
785     MSVT =
786         getMSVCVersionFromExe(getSubDirectoryPath(llvm::SubDirectoryType::Bin));
787   if (MSVT.empty() &&
788       Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
789                    IsWindowsMSVC)) {
790     // -fms-compatibility-version=19.33 is default, aka 2022, 17.3
791     // NOTE: when changing this value, also update
792     // clang/docs/CommandGuide/clang.rst and clang/docs/UsersManual.rst
793     // accordingly.
794     MSVT = VersionTuple(19, 33);
795   }
796   return MSVT;
797 }
798 
799 std::string
ComputeEffectiveClangTriple(const ArgList & Args,types::ID InputType) const800 MSVCToolChain::ComputeEffectiveClangTriple(const ArgList &Args,
801                                            types::ID InputType) const {
802   // The MSVC version doesn't care about the architecture, even though it
803   // may look at the triple internally.
804   VersionTuple MSVT = computeMSVCVersion(/*D=*/nullptr, Args);
805   MSVT = VersionTuple(MSVT.getMajor(), MSVT.getMinor().value_or(0),
806                       MSVT.getSubminor().value_or(0));
807 
808   // For the rest of the triple, however, a computed architecture name may
809   // be needed.
810   llvm::Triple Triple(ToolChain::ComputeEffectiveClangTriple(Args, InputType));
811   if (Triple.getEnvironment() == llvm::Triple::MSVC) {
812     StringRef ObjFmt = Triple.getEnvironmentName().split('-').second;
813     if (ObjFmt.empty())
814       Triple.setEnvironmentName((Twine("msvc") + MSVT.getAsString()).str());
815     else
816       Triple.setEnvironmentName(
817           (Twine("msvc") + MSVT.getAsString() + Twine('-') + ObjFmt).str());
818   }
819   return Triple.getTriple();
820 }
821 
getSupportedSanitizers() const822 SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
823   SanitizerMask Res = ToolChain::getSupportedSanitizers();
824   Res |= SanitizerKind::Address;
825   Res |= SanitizerKind::PointerCompare;
826   Res |= SanitizerKind::PointerSubtract;
827   Res |= SanitizerKind::Fuzzer;
828   Res |= SanitizerKind::FuzzerNoLink;
829   Res &= ~SanitizerKind::CFIMFCall;
830   return Res;
831 }
832 
TranslateOptArg(Arg * A,llvm::opt::DerivedArgList & DAL,bool SupportsForcingFramePointer,const char * ExpandChar,const OptTable & Opts)833 static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
834                             bool SupportsForcingFramePointer,
835                             const char *ExpandChar, const OptTable &Opts) {
836   assert(A->getOption().matches(options::OPT__SLASH_O));
837 
838   StringRef OptStr = A->getValue();
839   for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
840     const char &OptChar = *(OptStr.data() + I);
841     switch (OptChar) {
842     default:
843       break;
844     case '1':
845     case '2':
846     case 'x':
847     case 'd':
848       // Ignore /O[12xd] flags that aren't the last one on the command line.
849       // Only the last one gets expanded.
850       if (&OptChar != ExpandChar) {
851         A->claim();
852         break;
853       }
854       if (OptChar == 'd') {
855         DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
856       } else {
857         if (OptChar == '1') {
858           DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
859         } else if (OptChar == '2' || OptChar == 'x') {
860           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
861           DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
862         }
863         if (SupportsForcingFramePointer &&
864             !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer))
865           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer));
866         if (OptChar == '1' || OptChar == '2')
867           DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections));
868       }
869       break;
870     case 'b':
871       if (I + 1 != E && isdigit(OptStr[I + 1])) {
872         switch (OptStr[I + 1]) {
873         case '0':
874           DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_inline));
875           break;
876         case '1':
877           DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_hint_functions));
878           break;
879         case '2':
880           DAL.AddFlagArg(A, Opts.getOption(options::OPT_finline_functions));
881           break;
882         }
883         ++I;
884       }
885       break;
886     case 'g':
887       A->claim();
888       break;
889     case 'i':
890       if (I + 1 != E && OptStr[I + 1] == '-') {
891         ++I;
892         DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
893       } else {
894         DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
895       }
896       break;
897     case 's':
898       DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
899       break;
900     case 't':
901       DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
902       break;
903     case 'y': {
904       bool OmitFramePointer = true;
905       if (I + 1 != E && OptStr[I + 1] == '-') {
906         OmitFramePointer = false;
907         ++I;
908       }
909       if (SupportsForcingFramePointer) {
910         if (OmitFramePointer)
911           DAL.AddFlagArg(A,
912                          Opts.getOption(options::OPT_fomit_frame_pointer));
913         else
914           DAL.AddFlagArg(
915               A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
916       } else {
917         // Don't warn about /Oy- in x86-64 builds (where
918         // SupportsForcingFramePointer is false).  The flag having no effect
919         // there is a compiler-internal optimization, and people shouldn't have
920         // to special-case their build files for x86-64 clang-cl.
921         A->claim();
922       }
923       break;
924     }
925     }
926   }
927 }
928 
TranslateDArg(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)929 static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
930                           const OptTable &Opts) {
931   assert(A->getOption().matches(options::OPT_D));
932 
933   StringRef Val = A->getValue();
934   size_t Hash = Val.find('#');
935   if (Hash == StringRef::npos || Hash > Val.find('=')) {
936     DAL.append(A);
937     return;
938   }
939 
940   std::string NewVal = std::string(Val);
941   NewVal[Hash] = '=';
942   DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
943 }
944 
TranslatePermissive(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)945 static void TranslatePermissive(Arg *A, llvm::opt::DerivedArgList &DAL,
946                                 const OptTable &Opts) {
947   DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase_));
948   DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_operator_names));
949 }
950 
TranslatePermissiveMinus(Arg * A,llvm::opt::DerivedArgList & DAL,const OptTable & Opts)951 static void TranslatePermissiveMinus(Arg *A, llvm::opt::DerivedArgList &DAL,
952                                      const OptTable &Opts) {
953   DAL.AddFlagArg(A, Opts.getOption(options::OPT__SLASH_Zc_twoPhase));
954   DAL.AddFlagArg(A, Opts.getOption(options::OPT_foperator_names));
955 }
956 
957 llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList & Args,StringRef BoundArch,Action::OffloadKind OFK) const958 MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
959                              StringRef BoundArch,
960                              Action::OffloadKind OFK) const {
961   DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
962   const OptTable &Opts = getDriver().getOpts();
963 
964   // /Oy and /Oy- don't have an effect on X86-64
965   bool SupportsForcingFramePointer = getArch() != llvm::Triple::x86_64;
966 
967   // The -O[12xd] flag actually expands to several flags.  We must desugar the
968   // flags so that options embedded can be negated.  For example, the '-O2' flag
969   // enables '-Oy'.  Expanding '-O2' into its constituent flags allows us to
970   // correctly handle '-O2 -Oy-' where the trailing '-Oy-' disables a single
971   // aspect of '-O2'.
972   //
973   // Note that this expansion logic only applies to the *last* of '[12xd]'.
974 
975   // First step is to search for the character we'd like to expand.
976   const char *ExpandChar = nullptr;
977   for (Arg *A : Args.filtered(options::OPT__SLASH_O)) {
978     StringRef OptStr = A->getValue();
979     for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
980       char OptChar = OptStr[I];
981       char PrevChar = I > 0 ? OptStr[I - 1] : '0';
982       if (PrevChar == 'b') {
983         // OptChar does not expand; it's an argument to the previous char.
984         continue;
985       }
986       if (OptChar == '1' || OptChar == '2' || OptChar == 'x' || OptChar == 'd')
987         ExpandChar = OptStr.data() + I;
988     }
989   }
990 
991   for (Arg *A : Args) {
992     if (A->getOption().matches(options::OPT__SLASH_O)) {
993       // The -O flag actually takes an amalgam of other options.  For example,
994       // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
995       TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
996     } else if (A->getOption().matches(options::OPT_D)) {
997       // Translate -Dfoo#bar into -Dfoo=bar.
998       TranslateDArg(A, *DAL, Opts);
999     } else if (A->getOption().matches(options::OPT__SLASH_permissive)) {
1000       // Expand /permissive
1001       TranslatePermissive(A, *DAL, Opts);
1002     } else if (A->getOption().matches(options::OPT__SLASH_permissive_)) {
1003       // Expand /permissive-
1004       TranslatePermissiveMinus(A, *DAL, Opts);
1005     } else if (OFK != Action::OFK_HIP) {
1006       // HIP Toolchain translates input args by itself.
1007       DAL->append(A);
1008     }
1009   }
1010 
1011   return DAL;
1012 }
1013 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind DeviceOffloadKind) const1014 void MSVCToolChain::addClangTargetOptions(
1015     const ArgList &DriverArgs, ArgStringList &CC1Args,
1016     Action::OffloadKind DeviceOffloadKind) const {
1017   // MSVC STL kindly allows removing all usages of typeid by defining
1018   // _HAS_STATIC_RTTI to 0. Do so, when compiling with -fno-rtti
1019   if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti,
1020                          /*Default=*/false))
1021     CC1Args.push_back("-D_HAS_STATIC_RTTI=0");
1022 }
1023