xref: /llvm-project/clang/unittests/Frontend/CompilerInvocationTest.cpp (revision 97100646d1b4526de1eac3aacdb0b098739c6ec9)
1 //===- unittests/Frontend/CompilerInvocationTest.cpp - CI 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 #include "clang/Frontend/CompilerInvocation.h"
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Frontend/TextDiagnosticBuffer.h"
12 #include "llvm/Support/Host.h"
13 
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 
17 using namespace llvm;
18 using namespace clang;
19 
20 using ::testing::Contains;
21 using ::testing::HasSubstr;
22 using ::testing::StrEq;
23 
24 namespace {
25 class CommandLineTest : public ::testing::Test {
26 public:
27   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
28   SmallVector<const char *, 32> GeneratedArgs;
29   SmallVector<std::string, 32> GeneratedArgsStorage;
30   CompilerInvocation Invocation;
31 
32   const char *operator()(const Twine &Arg) {
33     return GeneratedArgsStorage.emplace_back(Arg.str()).c_str();
34   }
35 
36   CommandLineTest()
37       : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions(),
38                                                   new TextDiagnosticBuffer())) {
39   }
40 };
41 
42 template <typename M>
43 std::string describeContainsN(M InnerMatcher, unsigned N, bool Negation) {
44   StringRef Contains = Negation ? "doesn't contain" : "contains";
45   StringRef Instance = N == 1 ? " instance " : " instances ";
46   StringRef Element = "of element that ";
47 
48   std::ostringstream Inner;
49   InnerMatcher.impl().DescribeTo(&Inner);
50 
51   return (Contains + " exactly " + Twine(N) + Instance + Element + Inner.str())
52       .str();
53 }
54 
55 MATCHER_P2(ContainsN, InnerMatcher, N,
56            describeContainsN(InnerMatcher, N, negation)) {
57   auto InnerMatches = [this](const auto &Element) {
58     ::testing::internal::DummyMatchResultListener InnerListener;
59     return InnerMatcher.impl().MatchAndExplain(Element, &InnerListener);
60   };
61 
62   return count_if(arg, InnerMatches) == N;
63 }
64 
65 TEST(ContainsN, Empty) {
66   const char *Array[] = {""};
67 
68   ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
69   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
70   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
71 }
72 
73 TEST(ContainsN, Zero) {
74   const char *Array[] = {"y"};
75 
76   ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
77   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
78   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
79 }
80 
81 TEST(ContainsN, One) {
82   const char *Array[] = {"a", "b", "x", "z"};
83 
84   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
85   ASSERT_THAT(Array, ContainsN(StrEq("x"), 1));
86   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
87 }
88 
89 TEST(ContainsN, Two) {
90   const char *Array[] = {"x", "a", "b", "x"};
91 
92   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
93   ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
94   ASSERT_THAT(Array, ContainsN(StrEq("x"), 2));
95 }
96 
97 // Boolean option with a keypath that defaults to true.
98 // The only flag with a negative spelling can set the keypath to false.
99 
100 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) {
101   const char *Args[] = {""};
102 
103   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
104   ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
105 
106   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
107 
108   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file"))));
109 }
110 
111 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) {
112   const char *Args[] = {"-fno-temp-file"};
113 
114   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
115   ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary);
116 
117   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
118 
119   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file")));
120 }
121 
122 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) {
123   const char *Args[] = {"-ftemp-file"};
124 
125   // Driver-only flag.
126   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
127   ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
128 }
129 
130 // Boolean option with a keypath that defaults to true.
131 // The flag with negative spelling can set the keypath to false.
132 // The flag with positive spelling can reset the keypath to true.
133 
134 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) {
135   const char *Args[] = {""};
136 
137   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
138   ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
139 
140   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
141   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
142   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink"))));
143 }
144 
145 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) {
146   const char *Args[] = {"-fno-autolink"};
147 
148   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
149   ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink);
150 
151   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
152   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink")));
153   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
154 }
155 
156 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) {
157   const char *Args[] = {"-fautolink"};
158 
159   // Driver-only flag.
160   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
161   ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
162 }
163 
164 // Boolean option with a keypath that defaults to false.
165 // The flag with negative spelling can set the keypath to true.
166 // The flag with positive spelling can reset the keypath to false.
167 
168 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) {
169   const char *Args[] = {""};
170 
171   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
172   ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
173 
174   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
175   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
176   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables"))));
177 }
178 
179 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) {
180   const char *Args[] = {"-gno-inline-line-tables"};
181 
182   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
183   ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables);
184 
185   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
186   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables")));
187   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
188 }
189 
190 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) {
191   const char *Args[] = {"-ginline-line-tables"};
192 
193   // Driver-only flag.
194   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
195   ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
196 }
197 
198 // Boolean option with a keypath that defaults to false.
199 // The flag with positive spelling can set the keypath to true.
200 // The flag with negative spelling can reset the keypath to false.
201 
202 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) {
203   const char *Args[] = {""};
204 
205   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
206   ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
207 
208   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
209   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash"))));
210   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
211 }
212 
213 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) {
214   const char *Args[] = {"-gcodeview-ghash"};
215 
216   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
217   ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash);
218 
219   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
220   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash")));
221   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
222 }
223 
224 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) {
225   const char *Args[] = {"-gno-codeview-ghash"};
226 
227   // Driver-only flag.
228   ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
229   ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
230 }
231 
232 // Boolean option with a keypath that defaults to an arbitrary expression.
233 // The flag with positive spelling can set the keypath to true.
234 // The flag with negative spelling can set the keypath to false.
235 
236 static constexpr unsigned PassManagerDefault =
237     !static_cast<unsigned>(LLVM_ENABLE_NEW_PASS_MANAGER);
238 
239 static constexpr const char *PassManagerResetByFlag =
240     LLVM_ENABLE_NEW_PASS_MANAGER ? "-fno-legacy-pass-manager"
241                                  : "-flegacy-pass-manager";
242 
243 static constexpr const char *PassManagerChangedByFlag =
244     LLVM_ENABLE_NEW_PASS_MANAGER ? "-flegacy-pass-manager"
245                                  : "-fno-legacy-pass-manager";
246 
247 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) {
248   const char *Args = {""};
249 
250   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
251   ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault);
252 
253   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
254 
255   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
256   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag))));
257 }
258 
259 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) {
260   const char *Args[] = {PassManagerChangedByFlag};
261 
262   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
263   ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, !PassManagerDefault);
264 
265   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
266   ASSERT_THAT(GeneratedArgs, Contains(StrEq(PassManagerChangedByFlag)));
267   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
268 }
269 
270 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) {
271   const char *Args[] = {PassManagerResetByFlag};
272 
273   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
274   ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault);
275 
276   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
277   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
278   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag))));
279 }
280 
281 // Boolean option that gets the CC1Option flag from a let statement (which
282 // is applied **after** the record is defined):
283 //
284 //   let Flags = [CC1Option] in {
285 //     defm option : BoolOption<...>;
286 //   }
287 
288 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) {
289   const char *Args[] = {""};
290 
291   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
292   ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
293 
294   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
295 
296   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
297   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
298 }
299 
300 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) {
301   const char *Args[] = {"-fdebug-pass-manager"};
302 
303   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
304   ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager);
305 
306   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
307 
308   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fdebug-pass-manager"), 1));
309   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
310 }
311 
312 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) {
313   const char *Args[] = {"-fno-debug-pass-manager"};
314 
315   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
316   ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
317 
318   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
319 
320   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
321   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
322 }
323 
324 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) {
325   const char *Args[] = {"-fmodules-strict-context-hash"};
326 
327   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
328 
329   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
330 
331   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash")));
332 }
333 
334 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) {
335   const char *TripleCStr = "i686-apple-darwin9";
336   const char *Args[] = {"-triple", TripleCStr};
337 
338   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
339 
340   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
341 
342   ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr)));
343 }
344 
345 TEST_F(CommandLineTest,  CanGenerateCC1CommandLineSeparateRequiredPresent) {
346   const std::string DefaultTriple =
347       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
348   const char *Args[] = {"-triple", DefaultTriple.c_str()};
349 
350   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
351 
352   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
353 
354   // Triple should always be emitted even if it is the default
355   ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
356 }
357 
358 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) {
359   const std::string DefaultTriple =
360       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
361   const char *Args[] = {""};
362 
363   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
364 
365   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
366 
367   // Triple should always be emitted even if it is the default
368   ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
369 }
370 
371 TEST_F(CommandLineTest, SeparateEnumNonDefault) {
372   const char *Args[] = {"-mrelocation-model", "static"};
373 
374   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
375   ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static);
376 
377   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
378 
379   // Non default relocation model.
380   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model")));
381   ASSERT_THAT(GeneratedArgs, Contains(StrEq("static")));
382   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static"))));
383 }
384 
385 TEST_F(CommandLineTest, SeparateEnumDefault) {
386   const char *Args[] = {"-mrelocation-model", "pic"};
387 
388   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
389   ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_);
390 
391   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
392 
393   // Default relocation model.
394   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model"))));
395   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic"))));
396   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic"))));
397 }
398 
399 TEST_F(CommandLineTest, JoinedEnumNonDefault) {
400   const char *Args[] = {"-fobjc-dispatch-method=non-legacy"};
401 
402   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
403   ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
404             CodeGenOptions::NonLegacy);
405 
406   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
407 
408   ASSERT_THAT(GeneratedArgs,
409               Contains(StrEq("-fobjc-dispatch-method=non-legacy")));
410   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
411   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy"))));
412 }
413 
414 TEST_F(CommandLineTest, JoinedEnumDefault) {
415   const char *Args[] = {"-fobjc-dispatch-method=legacy"};
416 
417   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
418   ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
419             CodeGenOptions::Legacy);
420 
421   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
422 
423   ASSERT_THAT(GeneratedArgs,
424               Not(Contains(StrEq("-fobjc-dispatch-method=legacy"))));
425   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
426   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
427 }
428 
429 TEST_F(CommandLineTest, StringVectorEmpty) {
430   const char *Args[] = {""};
431 
432   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
433   ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
434 
435   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
436 
437   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file"))));
438 }
439 
440 TEST_F(CommandLineTest, StringVectorSingle) {
441   const char *Args[] = {"-fmodule-map-file=a"};
442 
443   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
444   ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles,
445             std::vector<std::string>({"a"}));
446 
447   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
448 
449   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
450   ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 1));
451 }
452 
453 TEST_F(CommandLineTest, StringVectorMultiple) {
454   const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"};
455 
456   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
457   ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles ==
458               std::vector<std::string>({"a", "b"}));
459 
460   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
461 
462   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
463   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=b"), 1));
464   ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 2));
465 }
466 
467 // CommaJoined option with MarshallingInfoStringVector.
468 
469 TEST_F(CommandLineTest, StringVectorCommaJoinedNone) {
470   const char *Args[] = {""};
471 
472   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
473   ASSERT_TRUE(Invocation.getLangOpts()->CommentOpts.BlockCommandNames.empty());
474 
475   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
476 
477   ASSERT_THAT(GeneratedArgs,
478               Not(Contains(HasSubstr("-fcomment-block-commands"))));
479 }
480 
481 TEST_F(CommandLineTest, StringVectorCommaJoinedSingle) {
482   const char *Args[] = {"-fcomment-block-commands=x,y"};
483 
484   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
485   ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames,
486             std::vector<std::string>({"x", "y"}));
487 
488   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
489 
490   ASSERT_THAT(GeneratedArgs,
491               ContainsN(StrEq("-fcomment-block-commands=x,y"), 1));
492 }
493 
494 TEST_F(CommandLineTest, StringVectorCommaJoinedMultiple) {
495   const char *Args[] = {"-fcomment-block-commands=x,y",
496                         "-fcomment-block-commands=a,b"};
497 
498   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
499   ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames,
500             std::vector<std::string>({"x", "y", "a", "b"}));
501 
502   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
503 
504   ASSERT_THAT(GeneratedArgs,
505               ContainsN(StrEq("-fcomment-block-commands=x,y,a,b"), 1));
506 }
507 
508 // A flag that should be parsed only if a condition is met.
509 
510 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagNotPresent) {
511   const char *Args[] = {""};
512 
513   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
514 
515   ASSERT_FALSE(Diags->hasErrorOccurred());
516   ASSERT_FALSE(Invocation.getLangOpts()->SYCL);
517   ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
518 
519   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
520 
521   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl"))));
522   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
523 }
524 
525 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagPresent) {
526   const char *Args[] = {"-sycl-std=2017"};
527 
528   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
529 
530   ASSERT_FALSE(Diags->hasErrorOccurred());
531   ASSERT_FALSE(Invocation.getLangOpts()->SYCL);
532   ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
533 
534   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
535 
536   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl"))));
537   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
538 }
539 
540 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresent) {
541   const char *Args[] = {"-fsycl"};
542 
543   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
544 
545   ASSERT_FALSE(Diags->hasErrorOccurred());
546   ASSERT_TRUE(Invocation.getLangOpts()->SYCL);
547   ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
548 
549   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
550 
551   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl")));
552   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
553 }
554 
555 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagPresent) {
556   const char *Args[] = {"-fsycl", "-sycl-std=2017"};
557 
558   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
559 
560   ASSERT_FALSE(Diags->hasErrorOccurred());
561   ASSERT_TRUE(Invocation.getLangOpts()->SYCL);
562   ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017);
563 
564   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
565 
566   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl")));
567   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-sycl-std=2017")));
568 }
569 
570 // Wide integer option.
571 
572 TEST_F(CommandLineTest, WideIntegerHighValue) {
573   const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"};
574 
575   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
576 
577   ASSERT_FALSE(Diags->hasErrorOccurred());
578   ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp,
579             1609827494445723662ull);
580 }
581 
582 // Tree of boolean options that can be (directly or transitively) implied by
583 // their parent:
584 //
585 //   * -cl-unsafe-math-optimizations
586 //     * -cl-mad-enable
587 //     * -menable-unsafe-fp-math
588 //       * -freciprocal-math
589 
590 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) {
591   const char *Args[] = {""};
592 
593   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
594   ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
595   ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
596   ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath);
597   ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip);
598 
599   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
600 
601   // Not generated - missing.
602   ASSERT_THAT(GeneratedArgs,
603               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
604   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
605   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
606   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
607 }
608 
609 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) {
610   const char *Args[] = {"-cl-unsafe-math-optimizations"};
611 
612   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
613   // Explicitly provided root flag.
614   ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
615   // Directly implied by explicitly provided root flag.
616   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
617   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
618   // Transitively implied by explicitly provided root flag.
619   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
620 
621   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
622 
623   // Generated - explicitly provided.
624   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
625   // Not generated - implied by the generated root flag.
626   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
627   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
628   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
629 }
630 
631 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) {
632   const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable",
633                         "-menable-unsafe-fp-math", "-freciprocal-math"};
634 
635   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
636   ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
637   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
638   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
639   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
640 
641   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
642 
643   // Generated - explicitly provided.
644   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
645   // Not generated - implied by their generated parent.
646   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
647   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
648   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
649 }
650 
651 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) {
652   const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math",
653                         "-freciprocal-math"};
654 
655   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
656   ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
657   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
658   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
659   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
660 
661   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
662   // Not generated - missing.
663   ASSERT_THAT(GeneratedArgs,
664               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
665   // Generated - explicitly provided.
666   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
667   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
668   // Not generated - implied by its generated parent.
669   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
670 }
671 
672 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) {
673   const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"};
674 
675   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
676 
677   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
678 
679   // Present options that were not implied are generated.
680   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
681   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
682 }
683 
684 // Diagnostic option.
685 
686 TEST_F(CommandLineTest, DiagnosticOptionPresent) {
687   const char *Args[] = {"-verify=xyz"};
688 
689   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
690 
691   ASSERT_EQ(Invocation.getDiagnosticOpts().VerifyPrefixes,
692             std::vector<std::string>({"xyz"}));
693 
694   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
695 
696   ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-verify=xyz"), 1));
697 }
698 } // anonymous namespace
699