Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / Driver / ToolChainTest.cpp
blobacbbb87390d5e9ae3a26586ac290f34059bd671c
1 //===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===//
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 // Unit tests for ToolChains.
11 //===----------------------------------------------------------------------===//
13 #include "clang/Driver/ToolChain.h"
14 #include "clang/Basic/DiagnosticIDs.h"
15 #include "clang/Basic/DiagnosticOptions.h"
16 #include "clang/Basic/LLVM.h"
17 #include "clang/Basic/TargetOptions.h"
18 #include "clang/Driver/Compilation.h"
19 #include "clang/Driver/Driver.h"
20 #include "clang/Frontend/CompilerInstance.h"
21 #include "llvm/ADT/ArrayRef.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/MC/TargetRegistry.h"
24 #include "llvm/Support/TargetSelect.h"
25 #include "llvm/Support/VirtualFileSystem.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include <memory>
31 #include "SimpleDiagnosticConsumer.h"
33 using namespace clang;
34 using namespace clang::driver;
36 namespace {
38 TEST(ToolChainTest, VFSGCCInstallation) {
39 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
41 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
42 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
43 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
44 new llvm::vfs::InMemoryFileSystem);
46 const char *EmptyFiles[] = {
47 "foo.cpp",
48 "/bin/clang",
49 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
50 "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o",
51 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o",
52 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o",
53 "/usr/lib/arm-linux-gnueabi/crt1.o",
54 "/usr/lib/arm-linux-gnueabi/crti.o",
55 "/usr/lib/arm-linux-gnueabi/crtn.o",
56 "/usr/lib/arm-linux-gnueabihf/crt1.o",
57 "/usr/lib/arm-linux-gnueabihf/crti.o",
58 "/usr/lib/arm-linux-gnueabihf/crtn.o",
59 "/usr/include/arm-linux-gnueabi/.keep",
60 "/usr/include/arm-linux-gnueabihf/.keep",
61 "/lib/arm-linux-gnueabi/.keep",
62 "/lib/arm-linux-gnueabihf/.keep",
64 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtbegin.o",
65 "/sysroot/usr/lib/gcc/arm-linux-gnueabi/4.5.1/crtend.o",
66 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtbegin.o",
67 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3/crtend.o",
68 "/sysroot/usr/lib/arm-linux-gnueabi/crt1.o",
69 "/sysroot/usr/lib/arm-linux-gnueabi/crti.o",
70 "/sysroot/usr/lib/arm-linux-gnueabi/crtn.o",
71 "/sysroot/usr/lib/arm-linux-gnueabihf/crt1.o",
72 "/sysroot/usr/lib/arm-linux-gnueabihf/crti.o",
73 "/sysroot/usr/lib/arm-linux-gnueabihf/crtn.o",
74 "/sysroot/usr/include/arm-linux-gnueabi/.keep",
75 "/sysroot/usr/include/arm-linux-gnueabihf/.keep",
76 "/sysroot/lib/arm-linux-gnueabi/.keep",
77 "/sysroot/lib/arm-linux-gnueabihf/.keep",
80 for (const char *Path : EmptyFiles)
81 InMemoryFileSystem->addFile(Path, 0,
82 llvm::MemoryBuffer::getMemBuffer("\n"));
85 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
86 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
87 "clang LLVM compiler", InMemoryFileSystem);
88 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
89 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=", "foo.cpp"}));
90 ASSERT_TRUE(C);
91 std::string S;
93 llvm::raw_string_ostream OS(S);
94 C->getDefaultToolChain().printVerboseInfo(OS);
96 if (is_style_windows(llvm::sys::path::Style::native))
97 std::replace(S.begin(), S.end(), '\\', '/');
98 EXPECT_EQ(
99 "Found candidate GCC installation: "
100 "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
101 "Selected GCC installation: /usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n"
102 "Candidate multilib: .;@m32\n"
103 "Selected multilib: .;@m32\n",
108 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
109 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
110 "clang LLVM compiler", InMemoryFileSystem);
111 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
112 {"-fsyntax-only", "--gcc-toolchain=", "--sysroot=/sysroot",
113 "foo.cpp"}));
114 ASSERT_TRUE(C);
115 std::string S;
117 llvm::raw_string_ostream OS(S);
118 C->getDefaultToolChain().printVerboseInfo(OS);
120 if (is_style_windows(llvm::sys::path::Style::native))
121 std::replace(S.begin(), S.end(), '\\', '/');
122 // Test that 4.5.3 from --sysroot is not overridden by 4.6.3 (larger
123 // version) from /usr.
124 EXPECT_EQ("Found candidate GCC installation: "
125 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
126 "Selected GCC installation: "
127 "/sysroot/usr/lib/gcc/arm-linux-gnueabihf/4.5.3\n"
128 "Candidate multilib: .;@m32\n"
129 "Selected multilib: .;@m32\n",
134 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
135 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
137 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
138 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
139 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
140 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
141 new llvm::vfs::InMemoryFileSystem);
142 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
143 "clang LLVM compiler", InMemoryFileSystem);
145 const char *EmptyFiles[] = {
146 "foo.cpp", "/home/test/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o",
147 "/home/test/include/arm-linux-gnueabi/.keep"};
149 for (const char *Path : EmptyFiles)
150 InMemoryFileSystem->addFile(Path, 0,
151 llvm::MemoryBuffer::getMemBuffer("\n"));
153 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
154 {"-fsyntax-only", "--gcc-toolchain=", "foo.cpp"}));
155 EXPECT_TRUE(C);
157 std::string S;
159 llvm::raw_string_ostream OS(S);
160 C->getDefaultToolChain().printVerboseInfo(OS);
162 if (is_style_windows(llvm::sys::path::Style::native))
163 std::replace(S.begin(), S.end(), '\\', '/');
164 EXPECT_EQ("Found candidate GCC installation: "
165 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
166 "Selected GCC installation: "
167 "/home/test/bin/../lib/gcc/arm-linux-gnueabi/4.6.1\n"
168 "Candidate multilib: .;@m32\n"
169 "Selected multilib: .;@m32\n",
173 TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
174 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
176 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
177 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
178 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
179 new llvm::vfs::InMemoryFileSystem);
181 const char *EmptyFiles[] = {
182 // Sort entries so the latest version doesn't come first.
183 "/usr/gcc/7/lib/gcc/sparcv9-sun-solaris2.11/7.5.0/32/crtbegin.o",
184 "/usr/gcc/7/lib/gcc/sparcv9-sun-solaris2.11/7.5.0/crtbegin.o",
185 "/usr/gcc/7/lib/gcc/x86_64-pc-solaris2.11/7.5.0/32/crtbegin.o",
186 "/usr/gcc/7/lib/gcc/x86_64-pc-solaris2.11/7.5.0/crtbegin.o",
187 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0/crtbegin.o",
188 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0/sparcv8plus/crtbegin.o",
189 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0/32/crtbegin.o",
190 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0/crtbegin.o",
191 "/usr/gcc/4.7/lib/gcc/i386-pc-solaris2.11/4.7.3/amd64/crtbegin.o",
192 "/usr/gcc/4.7/lib/gcc/i386-pc-solaris2.11/4.7.3/crtbegin.o",
193 "/usr/gcc/4.7/lib/gcc/sparc-sun-solaris2.11/4.7.3/crtbegin.o",
194 "/usr/gcc/4.7/lib/gcc/sparc-sun-solaris2.11/4.7.3/sparcv9/crtbegin.o",
197 for (const char *Path : EmptyFiles)
198 InMemoryFileSystem->addFile(Path, 0,
199 llvm::MemoryBuffer::getMemBuffer("\n"));
202 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
203 Driver TheDriver("/bin/clang", "i386-pc-solaris2.11", Diags,
204 "clang LLVM compiler", InMemoryFileSystem);
205 std::unique_ptr<Compilation> C(
206 TheDriver.BuildCompilation({"-v", "--gcc-toolchain=", "--sysroot="}));
207 ASSERT_TRUE(C);
208 std::string S;
210 llvm::raw_string_ostream OS(S);
211 C->getDefaultToolChain().printVerboseInfo(OS);
213 if (is_style_windows(llvm::sys::path::Style::native))
214 std::replace(S.begin(), S.end(), '\\', '/');
215 EXPECT_EQ("Found candidate GCC installation: "
216 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
217 "Selected GCC installation: "
218 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
219 "Candidate multilib: .;@m64\n"
220 "Candidate multilib: 32;@m32\n"
221 "Selected multilib: 32;@m32\n",
226 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
227 Driver TheDriver("/bin/clang", "amd64-pc-solaris2.11", Diags,
228 "clang LLVM compiler", InMemoryFileSystem);
229 std::unique_ptr<Compilation> C(
230 TheDriver.BuildCompilation({"-v", "--gcc-toolchain=", "--sysroot="}));
231 ASSERT_TRUE(C);
232 std::string S;
234 llvm::raw_string_ostream OS(S);
235 C->getDefaultToolChain().printVerboseInfo(OS);
237 if (is_style_windows(llvm::sys::path::Style::native))
238 std::replace(S.begin(), S.end(), '\\', '/');
239 EXPECT_EQ("Found candidate GCC installation: "
240 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
241 "Selected GCC installation: "
242 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
243 "Candidate multilib: .;@m64\n"
244 "Candidate multilib: 32;@m32\n"
245 "Selected multilib: .;@m64\n",
250 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
251 Driver TheDriver("/bin/clang", "x86_64-pc-solaris2.11", Diags,
252 "clang LLVM compiler", InMemoryFileSystem);
253 std::unique_ptr<Compilation> C(
254 TheDriver.BuildCompilation({"-v", "--gcc-toolchain=", "--sysroot="}));
255 ASSERT_TRUE(C);
256 std::string S;
258 llvm::raw_string_ostream OS(S);
259 C->getDefaultToolChain().printVerboseInfo(OS);
261 if (is_style_windows(llvm::sys::path::Style::native))
262 std::replace(S.begin(), S.end(), '\\', '/');
263 EXPECT_EQ("Found candidate GCC installation: "
264 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
265 "Selected GCC installation: "
266 "/usr/gcc/11/lib/gcc/x86_64-pc-solaris2.11/11.4.0\n"
267 "Candidate multilib: .;@m64\n"
268 "Candidate multilib: 32;@m32\n"
269 "Selected multilib: .;@m64\n",
274 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
275 Driver TheDriver("/bin/clang", "sparc-sun-solaris2.11", Diags,
276 "clang LLVM compiler", InMemoryFileSystem);
277 std::unique_ptr<Compilation> C(
278 TheDriver.BuildCompilation({"-v", "--gcc-toolchain=", "--sysroot="}));
279 ASSERT_TRUE(C);
280 std::string S;
282 llvm::raw_string_ostream OS(S);
283 C->getDefaultToolChain().printVerboseInfo(OS);
285 if (is_style_windows(llvm::sys::path::Style::native))
286 std::replace(S.begin(), S.end(), '\\', '/');
287 EXPECT_EQ("Found candidate GCC installation: "
288 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
289 "Selected GCC installation: "
290 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
291 "Candidate multilib: .;@m64\n"
292 "Candidate multilib: sparcv8plus;@m32\n"
293 "Selected multilib: sparcv8plus;@m32\n",
297 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
298 Driver TheDriver("/bin/clang", "sparcv9-sun-solaris2.11", Diags,
299 "clang LLVM compiler", InMemoryFileSystem);
300 std::unique_ptr<Compilation> C(
301 TheDriver.BuildCompilation({"-v", "--gcc-toolchain=", "--sysroot="}));
302 ASSERT_TRUE(C);
303 std::string S;
305 llvm::raw_string_ostream OS(S);
306 C->getDefaultToolChain().printVerboseInfo(OS);
308 if (is_style_windows(llvm::sys::path::Style::native))
309 std::replace(S.begin(), S.end(), '\\', '/');
310 EXPECT_EQ("Found candidate GCC installation: "
311 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
312 "Selected GCC installation: "
313 "/usr/gcc/11/lib/gcc/sparcv9-sun-solaris2.11/11.4.0\n"
314 "Candidate multilib: .;@m64\n"
315 "Candidate multilib: sparcv8plus;@m32\n"
316 "Selected multilib: .;@m64\n",
321 MATCHER_P(jobHasArgs, Substr, "") {
322 const driver::Command &C = arg;
323 std::string Args = "";
324 llvm::ListSeparator Sep(" ");
325 for (const char *Arg : C.getArguments()) {
326 Args += Sep;
327 Args += Arg;
329 if (is_style_windows(llvm::sys::path::Style::native))
330 std::replace(Args.begin(), Args.end(), '\\', '/');
331 if (llvm::StringRef(Args).contains(Substr))
332 return true;
333 *result_listener << "whose args are '" << Args << "'";
334 return false;
337 TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
338 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
340 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
341 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
342 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
343 new llvm::vfs::InMemoryFileSystem);
345 const char *EmptyFiles[] = {
346 "foo.cpp",
347 "/bin/clang",
348 "/usr/include/c++/v1/cstdio",
351 for (const char *Path : EmptyFiles)
352 InMemoryFileSystem->addFile(Path, 0,
353 llvm::MemoryBuffer::getMemBuffer("\n"));
356 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
357 Driver TheDriver("/bin/clang", "x86_64-unknown-linux-gnu", Diags,
358 "clang LLVM compiler", InMemoryFileSystem);
359 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
360 {"/bin/clang", "-fsyntax-only", "-stdlib=libc++",
361 "--sysroot=", "foo.cpp"}));
362 ASSERT_TRUE(C);
363 EXPECT_THAT(C->getJobs(), testing::ElementsAre(jobHasArgs(
364 "-internal-isystem /usr/include/c++/v1")));
368 TEST(ToolChainTest, DefaultDriverMode) {
369 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
371 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
372 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
373 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
374 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
375 new llvm::vfs::InMemoryFileSystem);
377 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
378 "clang LLVM compiler", InMemoryFileSystem);
379 CCDriver.setCheckInputsExist(false);
380 Driver CXXDriver("/home/test/bin/clang++", "arm-linux-gnueabi", Diags,
381 "clang LLVM compiler", InMemoryFileSystem);
382 CXXDriver.setCheckInputsExist(false);
383 Driver CLDriver("/home/test/bin/clang-cl", "arm-linux-gnueabi", Diags,
384 "clang LLVM compiler", InMemoryFileSystem);
385 CLDriver.setCheckInputsExist(false);
387 std::unique_ptr<Compilation> CC(CCDriver.BuildCompilation(
388 { "/home/test/bin/clang", "foo.cpp"}));
389 std::unique_ptr<Compilation> CXX(CXXDriver.BuildCompilation(
390 { "/home/test/bin/clang++", "foo.cpp"}));
391 std::unique_ptr<Compilation> CL(CLDriver.BuildCompilation(
392 { "/home/test/bin/clang-cl", "foo.cpp"}));
394 EXPECT_TRUE(CC);
395 EXPECT_TRUE(CXX);
396 EXPECT_TRUE(CL);
397 EXPECT_TRUE(CCDriver.CCCIsCC());
398 EXPECT_TRUE(CXXDriver.CCCIsCXX());
399 EXPECT_TRUE(CLDriver.IsCLMode());
401 TEST(ToolChainTest, InvalidArgument) {
402 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
403 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
404 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
405 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
406 Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
407 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
408 {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
409 EXPECT_TRUE(C);
410 EXPECT_TRUE(C->containsError());
413 TEST(ToolChainTest, ParsedClangName) {
414 ParsedClangName Empty;
415 EXPECT_TRUE(Empty.TargetPrefix.empty());
416 EXPECT_TRUE(Empty.ModeSuffix.empty());
417 EXPECT_TRUE(Empty.DriverMode == nullptr);
418 EXPECT_FALSE(Empty.TargetIsValid);
420 ParsedClangName DriverOnly("clang", nullptr);
421 EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
422 EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
423 EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
424 EXPECT_FALSE(DriverOnly.TargetIsValid);
426 ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
427 EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
428 EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
429 EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
430 EXPECT_FALSE(DriverOnly2.TargetIsValid);
432 ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
433 EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
434 EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
435 EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
436 EXPECT_TRUE(TargetAndMode.TargetIsValid);
439 TEST(ToolChainTest, GetTargetAndMode) {
440 llvm::InitializeAllTargets();
441 std::string IgnoredError;
442 if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError))
443 GTEST_SKIP();
445 ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang");
446 EXPECT_TRUE(Res.TargetPrefix.empty());
447 EXPECT_TRUE(Res.ModeSuffix == "clang");
448 EXPECT_TRUE(Res.DriverMode == nullptr);
449 EXPECT_FALSE(Res.TargetIsValid);
451 Res = ToolChain::getTargetAndModeFromProgramName("clang++");
452 EXPECT_TRUE(Res.TargetPrefix.empty());
453 EXPECT_TRUE(Res.ModeSuffix == "clang++");
454 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
455 EXPECT_FALSE(Res.TargetIsValid);
457 Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0");
458 EXPECT_TRUE(Res.TargetPrefix.empty());
459 EXPECT_TRUE(Res.ModeSuffix == "clang++");
460 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
461 EXPECT_FALSE(Res.TargetIsValid);
463 Res = ToolChain::getTargetAndModeFromProgramName("clang++-release");
464 EXPECT_TRUE(Res.TargetPrefix.empty());
465 EXPECT_TRUE(Res.ModeSuffix == "clang++");
466 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
467 EXPECT_FALSE(Res.TargetIsValid);
469 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++");
470 EXPECT_TRUE(Res.TargetPrefix == "x86_64");
471 EXPECT_TRUE(Res.ModeSuffix == "clang++");
472 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
473 EXPECT_TRUE(Res.TargetIsValid);
475 Res = ToolChain::getTargetAndModeFromProgramName(
476 "x86_64-linux-gnu-clang-c++");
477 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
478 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
479 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
480 EXPECT_TRUE(Res.TargetIsValid);
482 Res = ToolChain::getTargetAndModeFromProgramName(
483 "x86_64-linux-gnu-clang-c++-tot");
484 EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
485 EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
486 EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
487 EXPECT_TRUE(Res.TargetIsValid);
489 Res = ToolChain::getTargetAndModeFromProgramName("qqq");
490 EXPECT_TRUE(Res.TargetPrefix.empty());
491 EXPECT_TRUE(Res.ModeSuffix.empty());
492 EXPECT_TRUE(Res.DriverMode == nullptr);
493 EXPECT_FALSE(Res.TargetIsValid);
495 Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq");
496 EXPECT_TRUE(Res.TargetPrefix.empty());
497 EXPECT_TRUE(Res.ModeSuffix.empty());
498 EXPECT_TRUE(Res.DriverMode == nullptr);
499 EXPECT_FALSE(Res.TargetIsValid);
501 Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl");
502 EXPECT_TRUE(Res.TargetPrefix == "qqq");
503 EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
504 EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
505 EXPECT_FALSE(Res.TargetIsValid);
507 Res = ToolChain::getTargetAndModeFromProgramName("clang-dxc");
508 EXPECT_TRUE(Res.TargetPrefix.empty());
509 EXPECT_TRUE(Res.ModeSuffix == "clang-dxc");
510 EXPECT_STREQ(Res.DriverMode, "--driver-mode=dxc");
511 EXPECT_FALSE(Res.TargetIsValid);
514 TEST(ToolChainTest, CommandOutput) {
515 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
517 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
518 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
519 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
520 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
521 new llvm::vfs::InMemoryFileSystem);
523 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
524 "clang LLVM compiler", InMemoryFileSystem);
525 CCDriver.setCheckInputsExist(false);
526 std::unique_ptr<Compilation> CC(
527 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"}));
528 const JobList &Jobs = CC->getJobs();
530 const auto &CmdCompile = Jobs.getJobs().front();
531 const auto &InFile = CmdCompile->getInputInfos().front().getFilename();
532 EXPECT_STREQ(InFile, "foo.cpp");
533 auto ObjFile = CmdCompile->getOutputFilenames().front();
534 EXPECT_TRUE(StringRef(ObjFile).endswith(".o"));
536 const auto &CmdLink = Jobs.getJobs().back();
537 const auto LinkInFile = CmdLink->getInputInfos().front().getFilename();
538 EXPECT_EQ(ObjFile, LinkInFile);
539 auto ExeFile = CmdLink->getOutputFilenames().front();
540 EXPECT_EQ("a.out", ExeFile);
543 TEST(ToolChainTest, PostCallback) {
544 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
545 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
546 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
547 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
548 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
549 new llvm::vfs::InMemoryFileSystem);
551 // The executable path must not exist.
552 Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
553 "clang LLVM compiler", InMemoryFileSystem);
554 CCDriver.setCheckInputsExist(false);
555 std::unique_ptr<Compilation> CC(
556 CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"}));
557 bool CallbackHasCalled = false;
558 CC->setPostCallback(
559 [&](const Command &C, int Ret) { CallbackHasCalled = true; });
560 const JobList &Jobs = CC->getJobs();
561 auto &CmdCompile = Jobs.getJobs().front();
562 const Command *FailingCmd = nullptr;
563 CC->ExecuteCommand(*CmdCompile, FailingCmd);
564 EXPECT_TRUE(CallbackHasCalled);
567 TEST(CompilerInvocation, SplitSwarfSingleCrash) {
568 static constexpr const char *Args[] = {
569 "clang", "--target=arm-linux-gnueabi",
570 "-gdwarf-4", "-gsplit-dwarf=single",
571 "-c", "foo.cpp"};
572 CreateInvocationOptions CIOpts;
573 std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, CIOpts);
574 EXPECT_TRUE(CI); // no-crash
577 TEST(GetDriverMode, PrefersLastDriverMode) {
578 static constexpr const char *Args[] = {"clang-cl", "--driver-mode=foo",
579 "--driver-mode=bar", "foo.cpp"};
580 EXPECT_EQ(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1)), "bar");
583 struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
584 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
585 const Diagnostic &Info) override {
586 if (DiagLevel == DiagnosticsEngine::Level::Error) {
587 Errors.emplace_back();
588 Info.FormatDiagnostic(Errors.back());
589 } else {
590 Msgs.emplace_back();
591 Info.FormatDiagnostic(Msgs.back());
594 void clear() override {
595 Msgs.clear();
596 Errors.clear();
597 DiagnosticConsumer::clear();
599 std::vector<SmallString<32>> Msgs;
600 std::vector<SmallString<32>> Errors;
603 TEST(ToolChainTest, ConfigFileSearch) {
604 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
605 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
606 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
607 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
608 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
609 new llvm::vfs::InMemoryFileSystem);
611 #ifdef _WIN32
612 const char *TestRoot = "C:\\";
613 #else
614 const char *TestRoot = "/";
615 #endif
616 FS->setCurrentWorkingDirectory(TestRoot);
618 FS->addFile(
619 "/opt/sdk/root.cfg", 0,
620 llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform0\n"));
621 FS->addFile(
622 "/home/test/sdk/root.cfg", 0,
623 llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform1\n"));
624 FS->addFile(
625 "/home/test/bin/root.cfg", 0,
626 llvm::MemoryBuffer::getMemBuffer("--sysroot=/opt/sdk/platform2\n"));
629 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
630 "clang LLVM compiler", FS);
631 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
632 {"/home/test/bin/clang", "--config", "root.cfg",
633 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
634 ASSERT_TRUE(C);
635 ASSERT_FALSE(C->containsError());
636 EXPECT_EQ("/opt/sdk/platform1", TheDriver.SysRoot);
639 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
640 "clang LLVM compiler", FS);
641 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
642 {"/home/test/bin/clang", "--config", "root.cfg",
643 "--config-system-dir=/opt/sdk", "--config-user-dir="}));
644 ASSERT_TRUE(C);
645 ASSERT_FALSE(C->containsError());
646 EXPECT_EQ("/opt/sdk/platform0", TheDriver.SysRoot);
649 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
650 "clang LLVM compiler", FS);
651 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
652 {"/home/test/bin/clang", "--config", "root.cfg",
653 "--config-system-dir=", "--config-user-dir="}));
654 ASSERT_TRUE(C);
655 ASSERT_FALSE(C->containsError());
656 EXPECT_EQ("/opt/sdk/platform2", TheDriver.SysRoot);
660 struct FileSystemWithError : public llvm::vfs::FileSystem {
661 llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
662 return std::make_error_code(std::errc::no_such_file_or_directory);
664 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
665 openFileForRead(const Twine &Path) override {
666 return std::make_error_code(std::errc::permission_denied);
668 llvm::vfs::directory_iterator dir_begin(const Twine &Dir,
669 std::error_code &EC) override {
670 return llvm::vfs::directory_iterator();
672 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
673 return std::make_error_code(std::errc::permission_denied);
675 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
676 return std::make_error_code(std::errc::permission_denied);
680 TEST(ToolChainTest, ConfigFileError) {
681 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
682 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
683 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
684 new SimpleDiagnosticConsumer());
685 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
686 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS(new FileSystemWithError);
688 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
689 "clang LLVM compiler", FS);
690 std::unique_ptr<Compilation> C(
691 TheDriver.BuildCompilation({"/home/test/bin/clang", "--no-default-config",
692 "--config", "./root.cfg", "--version"}));
693 ASSERT_TRUE(C);
694 ASSERT_TRUE(C->containsError());
695 EXPECT_EQ(1U, Diags.getNumErrors());
696 EXPECT_STREQ("configuration file './root.cfg' cannot be opened: cannot get "
697 "absolute path",
698 DiagConsumer->Errors[0].c_str());
701 TEST(ToolChainTest, BadConfigFile) {
702 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
703 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
704 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
705 new SimpleDiagnosticConsumer());
706 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
707 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
708 new llvm::vfs::InMemoryFileSystem);
710 #ifdef _WIN32
711 const char *TestRoot = "C:\\";
712 #define FILENAME "C:/opt/root.cfg"
713 #define DIRNAME "C:/opt"
714 #else
715 const char *TestRoot = "/";
716 #define FILENAME "/opt/root.cfg"
717 #define DIRNAME "/opt"
718 #endif
719 // UTF-16 string must be aligned on 2-byte boundary. Strings and char arrays
720 // do not provide necessary alignment, so copy constant string into properly
721 // allocated memory in heap.
722 llvm::BumpPtrAllocator Alloc;
723 char *StrBuff = (char *)Alloc.Allocate(16, 4);
724 std::memset(StrBuff, 0, 16);
725 std::memcpy(StrBuff, "\xFF\xFE\x00\xD8\x00\x00", 6);
726 StringRef BadUTF(StrBuff, 6);
727 FS->setCurrentWorkingDirectory(TestRoot);
728 FS->addFile("/opt/root.cfg", 0, llvm::MemoryBuffer::getMemBuffer(BadUTF));
729 FS->addFile("/home/user/test.cfg", 0,
730 llvm::MemoryBuffer::getMemBuffer("@file.rsp"));
733 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
734 "clang LLVM compiler", FS);
735 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
736 {"/home/test/bin/clang", "--config", "/opt/root.cfg", "--version"}));
737 ASSERT_TRUE(C);
738 ASSERT_TRUE(C->containsError());
739 EXPECT_EQ(1U, DiagConsumer->Errors.size());
740 EXPECT_STREQ("cannot read configuration file '" FILENAME
741 "': Could not convert UTF16 to UTF8",
742 DiagConsumer->Errors[0].c_str());
744 DiagConsumer->clear();
746 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
747 "clang LLVM compiler", FS);
748 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
749 {"/home/test/bin/clang", "--config", "/opt", "--version"}));
750 ASSERT_TRUE(C);
751 ASSERT_TRUE(C->containsError());
752 EXPECT_EQ(1U, DiagConsumer->Errors.size());
753 EXPECT_STREQ("configuration file '" DIRNAME
754 "' cannot be opened: not a regular file",
755 DiagConsumer->Errors[0].c_str());
757 DiagConsumer->clear();
759 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
760 "clang LLVM compiler", FS);
761 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
762 {"/home/test/bin/clang", "--config", "root",
763 "--config-system-dir=", "--config-user-dir=", "--version"}));
764 ASSERT_TRUE(C);
765 ASSERT_TRUE(C->containsError());
766 EXPECT_EQ(1U, DiagConsumer->Errors.size());
767 EXPECT_STREQ("configuration file 'root' cannot be found",
768 DiagConsumer->Errors[0].c_str());
771 #undef FILENAME
772 #undef DIRNAME
775 TEST(ToolChainTest, ConfigInexistentInclude) {
776 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
777 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
778 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
779 new SimpleDiagnosticConsumer());
780 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
781 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
782 new llvm::vfs::InMemoryFileSystem);
784 #ifdef _WIN32
785 const char *TestRoot = "C:\\";
786 #define USERCONFIG "C:\\home\\user\\test.cfg"
787 #define UNEXISTENT "C:\\home\\user\\file.rsp"
788 #else
789 const char *TestRoot = "/";
790 #define USERCONFIG "/home/user/test.cfg"
791 #define UNEXISTENT "/home/user/file.rsp"
792 #endif
793 FS->setCurrentWorkingDirectory(TestRoot);
794 FS->addFile("/home/user/test.cfg", 0,
795 llvm::MemoryBuffer::getMemBuffer("@file.rsp"));
798 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
799 "clang LLVM compiler", FS);
800 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
801 {"/home/test/bin/clang", "--config", "test.cfg",
802 "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
803 ASSERT_TRUE(C);
804 ASSERT_TRUE(C->containsError());
805 EXPECT_EQ(1U, DiagConsumer->Errors.size());
806 EXPECT_STRCASEEQ("cannot read configuration file '" USERCONFIG
807 "': cannot not open file '" UNEXISTENT
808 "': no such file or directory",
809 DiagConsumer->Errors[0].c_str());
812 #undef USERCONFIG
813 #undef UNEXISTENT
816 TEST(ToolChainTest, ConfigRecursiveInclude) {
817 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
818 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
819 std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
820 new SimpleDiagnosticConsumer());
821 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
822 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
823 new llvm::vfs::InMemoryFileSystem);
825 #ifdef _WIN32
826 const char *TestRoot = "C:\\";
827 #define USERCONFIG "C:\\home\\user\\test.cfg"
828 #define INCLUDED1 "C:\\home\\user\\file1.cfg"
829 #else
830 const char *TestRoot = "/";
831 #define USERCONFIG "/home/user/test.cfg"
832 #define INCLUDED1 "/home/user/file1.cfg"
833 #endif
834 FS->setCurrentWorkingDirectory(TestRoot);
835 FS->addFile("/home/user/test.cfg", 0,
836 llvm::MemoryBuffer::getMemBuffer("@file1.cfg"));
837 FS->addFile("/home/user/file1.cfg", 0,
838 llvm::MemoryBuffer::getMemBuffer("@file2.cfg"));
839 FS->addFile("/home/user/file2.cfg", 0,
840 llvm::MemoryBuffer::getMemBuffer("@file3.cfg"));
841 FS->addFile("/home/user/file3.cfg", 0,
842 llvm::MemoryBuffer::getMemBuffer("@file1.cfg"));
845 Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
846 "clang LLVM compiler", FS);
847 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
848 {"/home/test/bin/clang", "--config", "test.cfg",
849 "--config-system-dir=", "--config-user-dir=/home/user", "--version"}));
850 ASSERT_TRUE(C);
851 ASSERT_TRUE(C->containsError());
852 EXPECT_EQ(1U, DiagConsumer->Errors.size());
853 EXPECT_STREQ("cannot read configuration file '" USERCONFIG
854 "': recursive expansion of: '" INCLUDED1 "'",
855 DiagConsumer->Errors[0].c_str());
858 #undef USERCONFIG
859 #undef INCLUDED1
862 TEST(ToolChainTest, NestedConfigFile) {
863 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
864 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
865 struct TestDiagnosticConsumer : public DiagnosticConsumer {};
866 DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
867 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
868 new llvm::vfs::InMemoryFileSystem);
870 #ifdef _WIN32
871 const char *TestRoot = "C:\\";
872 #else
873 const char *TestRoot = "/";
874 #endif
875 FS->setCurrentWorkingDirectory(TestRoot);
877 FS->addFile("/opt/sdk/root.cfg", 0,
878 llvm::MemoryBuffer::getMemBuffer("--config=platform.cfg\n"));
879 FS->addFile("/opt/sdk/platform.cfg", 0,
880 llvm::MemoryBuffer::getMemBuffer("--sysroot=/platform-sys\n"));
881 FS->addFile("/home/test/bin/platform.cfg", 0,
882 llvm::MemoryBuffer::getMemBuffer("--sysroot=/platform-bin\n"));
884 SmallString<128> ClangExecutable("/home/test/bin/clang");
885 FS->makeAbsolute(ClangExecutable);
887 // User file is absent - use system definitions.
889 Driver TheDriver(ClangExecutable, "arm-linux-gnueabi", Diags,
890 "clang LLVM compiler", FS);
891 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
892 {"/home/test/bin/clang", "--config", "root.cfg",
893 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
894 ASSERT_TRUE(C);
895 ASSERT_FALSE(C->containsError());
896 EXPECT_EQ("/platform-sys", TheDriver.SysRoot);
899 // User file overrides system definitions.
900 FS->addFile("/home/test/sdk/platform.cfg", 0,
901 llvm::MemoryBuffer::getMemBuffer("--sysroot=/platform-user\n"));
903 Driver TheDriver(ClangExecutable, "arm-linux-gnueabi", Diags,
904 "clang LLVM compiler", FS);
905 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
906 {"/home/test/bin/clang", "--config", "root.cfg",
907 "--config-system-dir=/opt/sdk", "--config-user-dir=/home/test/sdk"}));
908 ASSERT_TRUE(C);
909 ASSERT_FALSE(C->containsError());
910 EXPECT_EQ("/platform-user", TheDriver.SysRoot);
914 } // end anonymous namespace.