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