xref: /llvm-project/clang/unittests/Frontend/CompilerInvocationTest.cpp (revision ce8c59e6af487f0b8786ae921aa926341f0ae04f)
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 // Boolean option with a keypath that defaults to true.
43 // The only flag with a negative spelling can set the keypath to false.
44 
45 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) {
46   const char *Args[] = {""};
47 
48   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
49 
50   ASSERT_FALSE(Diags->hasErrorOccurred());
51   ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
52 
53   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
54 
55   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file"))));
56 }
57 
58 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) {
59   const char *Args[] = {"-fno-temp-file"};
60 
61   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
62 
63   ASSERT_FALSE(Diags->hasErrorOccurred());
64   ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary);
65 
66   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
67 
68   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file")));
69 }
70 
71 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) {
72   const char *Args[] = {"-ftemp-file"};
73 
74   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
75 
76   // Driver-only flag.
77   ASSERT_TRUE(Diags->hasErrorOccurred());
78   ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
79 }
80 
81 // Boolean option with a keypath that defaults to true.
82 // The flag with negative spelling can set the keypath to false.
83 // The flag with positive spelling can reset the keypath to true.
84 
85 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) {
86   const char *Args[] = {""};
87 
88   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
89   ASSERT_FALSE(Diags->hasErrorOccurred());
90   ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
91 
92   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
93   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
94   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink"))));
95 }
96 
97 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) {
98   const char *Args[] = {"-fno-autolink"};
99 
100   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
101   ASSERT_FALSE(Diags->hasErrorOccurred());
102   ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink);
103 
104   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
105   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink")));
106   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
107 }
108 
109 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) {
110   const char *Args[] = {"-fautolink"};
111 
112   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
113   ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag.
114   ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
115 }
116 
117 // Boolean option with a keypath that defaults to false.
118 // The flag with negative spelling can set the keypath to true.
119 // The flag with positive spelling can reset the keypath to false.
120 
121 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) {
122   const char *Args[] = {""};
123 
124   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
125   ASSERT_FALSE(Diags->hasErrorOccurred());
126   ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
127 
128   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
129   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
130   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables"))));
131 }
132 
133 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) {
134   const char *Args[] = {"-gno-inline-line-tables"};
135 
136   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
137   ASSERT_FALSE(Diags->hasErrorOccurred());
138   ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables);
139 
140   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
141   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables")));
142   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
143 }
144 
145 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) {
146   const char *Args[] = {"-ginline-line-tables"};
147 
148   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
149   ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag.
150   ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
151 }
152 
153 // Boolean option with a keypath that defaults to false.
154 // The flag with positive spelling can set the keypath to true.
155 // The flag with negative spelling can reset the keypath to false.
156 
157 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) {
158   const char *Args[] = {""};
159 
160   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
161   ASSERT_FALSE(Diags->hasErrorOccurred());
162   ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
163 
164   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
165   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash"))));
166   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
167 }
168 
169 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) {
170   const char *Args[] = {"-gcodeview-ghash"};
171 
172   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
173   ASSERT_FALSE(Diags->hasErrorOccurred());
174   ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash);
175 
176   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
177   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash")));
178   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
179 }
180 
181 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) {
182   const char *Args[] = {"-gno-codeview-ghash"};
183 
184   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
185   ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag.
186   ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
187 }
188 
189 // Boolean option with a keypath that defaults to an arbitrary expression.
190 // The flag with positive spelling can set the keypath to true.
191 // The flag with negative spelling can set the keypath to false.
192 
193 static constexpr unsigned PassManagerDefault =
194     !static_cast<unsigned>(LLVM_ENABLE_NEW_PASS_MANAGER);
195 
196 static constexpr const char *PassManagerResetByFlag =
197     LLVM_ENABLE_NEW_PASS_MANAGER ? "-fno-legacy-pass-manager"
198                                  : "-flegacy-pass-manager";
199 
200 static constexpr const char *PassManagerChangedByFlag =
201     LLVM_ENABLE_NEW_PASS_MANAGER ? "-flegacy-pass-manager"
202                                  : "-fno-legacy-pass-manager";
203 
204 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) {
205   const char *Args = {""};
206 
207   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
208 
209   ASSERT_FALSE(Diags->hasErrorOccurred());
210   ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault);
211 
212   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
213 
214   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
215   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag))));
216 }
217 
218 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) {
219   const char *Args[] = {PassManagerChangedByFlag};
220 
221   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
222   ASSERT_FALSE(Diags->hasErrorOccurred());
223   ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, !PassManagerDefault);
224 
225   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
226   ASSERT_THAT(GeneratedArgs, Contains(StrEq(PassManagerChangedByFlag)));
227   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
228 }
229 
230 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) {
231   const char *Args[] = {PassManagerResetByFlag};
232 
233   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
234   ASSERT_FALSE(Diags->hasErrorOccurred());
235   ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault);
236 
237   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
238   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
239   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag))));
240 }
241 
242 // Boolean option that gets the CC1Option flag from a let statement (which
243 // is applied **after** the record is defined):
244 //
245 //   let Flags = [CC1Option] in {
246 //     defm option : BoolOption<...>;
247 //   }
248 
249 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) {
250   const char *Args[] = {""};
251 
252   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
253 
254   ASSERT_FALSE(Diags->hasErrorOccurred());
255   ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
256 
257   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
258 
259   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
260   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
261 }
262 
263 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) {
264   const char *Args[] = {"-fdebug-pass-manager"};
265 
266   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
267 
268   ASSERT_FALSE(Diags->hasErrorOccurred());
269   ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager);
270 
271   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
272 
273   ASSERT_EQ(count(GeneratedArgs, StringRef("-fdebug-pass-manager")), 1);
274   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
275 }
276 
277 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) {
278   const char *Args[] = {"-fno-debug-pass-manager"};
279 
280   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
281 
282   ASSERT_FALSE(Diags->hasErrorOccurred());
283   ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
284 
285   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
286 
287   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
288   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
289 }
290 
291 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) {
292   const char *Args[] = {"-fmodules-strict-context-hash"};
293 
294   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
295 
296   ASSERT_FALSE(Diags->hasErrorOccurred());
297 
298   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
299 
300   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash")));
301 }
302 
303 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) {
304   const char *TripleCStr = "i686-apple-darwin9";
305   const char *Args[] = {"-triple", TripleCStr};
306 
307   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
308 
309   ASSERT_FALSE(Diags->hasErrorOccurred());
310 
311   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
312 
313   ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr)));
314 }
315 
316 TEST_F(CommandLineTest,  CanGenerateCC1CommandLineSeparateRequiredPresent) {
317   const std::string DefaultTriple =
318       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
319   const char *Args[] = {"-triple", DefaultTriple.c_str()};
320 
321   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
322 
323   ASSERT_FALSE(Diags->hasErrorOccurred());
324 
325   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
326 
327   // Triple should always be emitted even if it is the default
328   ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
329 }
330 
331 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) {
332   const std::string DefaultTriple =
333       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
334   const char *Args[] = {""};
335 
336   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
337 
338   ASSERT_FALSE(Diags->hasErrorOccurred());
339 
340   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
341 
342   // Triple should always be emitted even if it is the default
343   ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
344 }
345 
346 TEST_F(CommandLineTest, SeparateEnumNonDefault) {
347   const char *Args[] = {"-mrelocation-model", "static"};
348 
349   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
350 
351   ASSERT_FALSE(Diags->hasErrorOccurred());
352   ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static);
353 
354   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
355 
356   // Non default relocation model.
357   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model")));
358   ASSERT_THAT(GeneratedArgs, Contains(StrEq("static")));
359   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static"))));
360 }
361 
362 TEST_F(CommandLineTest, SeparateEnumDefault) {
363   const char *Args[] = {"-mrelocation-model", "pic"};
364 
365   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
366 
367   ASSERT_FALSE(Diags->hasErrorOccurred());
368   ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_);
369 
370   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
371 
372   // Default relocation model.
373   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model"))));
374   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic"))));
375   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic"))));
376 }
377 
378 TEST_F(CommandLineTest, JoinedEnumNonDefault) {
379   const char *Args[] = {"-fobjc-dispatch-method=non-legacy"};
380 
381   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
382 
383   ASSERT_FALSE(Diags->hasErrorOccurred());
384   ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
385             CodeGenOptions::NonLegacy);
386 
387   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
388 
389   ASSERT_THAT(GeneratedArgs,
390               Contains(StrEq("-fobjc-dispatch-method=non-legacy")));
391   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
392   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy"))));
393 }
394 
395 TEST_F(CommandLineTest, JoinedEnumDefault) {
396   const char *Args[] = {"-fobjc-dispatch-method=legacy"};
397 
398   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
399 
400   ASSERT_FALSE(Diags->hasErrorOccurred());
401   ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
402             CodeGenOptions::Legacy);
403 
404   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
405 
406   ASSERT_THAT(GeneratedArgs,
407               Not(Contains(StrEq("-fobjc-dispatch-method=legacy"))));
408   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
409   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
410 }
411 
412 TEST_F(CommandLineTest, StringVectorEmpty) {
413   const char *Args[] = {""};
414 
415   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
416 
417   ASSERT_FALSE(Diags->hasErrorOccurred());
418   ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
419 
420   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
421   ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file="))));
422 }
423 
424 TEST_F(CommandLineTest, StringVectorSingle) {
425   const char *Args[] = {"-fmodule-map-file=a"};
426 
427   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
428 
429   ASSERT_FALSE(Diags->hasErrorOccurred());
430   ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles,
431             std::vector<std::string>({"a"}));
432 
433   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
434   ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1);
435 }
436 
437 TEST_F(CommandLineTest, StringVectorMultiple) {
438   const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"};
439 
440   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
441 
442   ASSERT_FALSE(Diags->hasErrorOccurred());
443   ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles ==
444               std::vector<std::string>({"a", "b"}));
445 
446   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
447   ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1);
448   ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=b")), 1);
449 }
450 
451 // Wide integer option.
452 
453 TEST_F(CommandLineTest, WideIntegerHighValue) {
454   const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"};
455 
456   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
457 
458   ASSERT_FALSE(Diags->hasErrorOccurred());
459   ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp,
460             1609827494445723662ull);
461 }
462 
463 // Tree of boolean options that can be (directly or transitively) implied by
464 // their parent:
465 //
466 //   * -cl-unsafe-math-optimizations
467 //     * -cl-mad-enable
468 //     * -menable-unsafe-fp-math
469 //       * -freciprocal-math
470 
471 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) {
472   const char *Args[] = {""};
473 
474   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
475 
476   ASSERT_FALSE(Diags->hasErrorOccurred());
477   ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
478   ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
479   ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath);
480   ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip);
481 
482   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
483 
484   // Not generated - missing.
485   ASSERT_THAT(GeneratedArgs,
486               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
487   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
488   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
489   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
490 }
491 
492 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) {
493   const char *Args[] = {"-cl-unsafe-math-optimizations"};
494 
495   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
496 
497   ASSERT_FALSE(Diags->hasErrorOccurred());
498   // Explicitly provided root flag.
499   ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
500   // Directly implied by explicitly provided root flag.
501   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
502   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
503   // Transitively implied by explicitly provided root flag.
504   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
505 
506   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
507 
508   // Generated - explicitly provided.
509   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
510   // Not generated - implied by the generated root flag.
511   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
512   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
513   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
514 }
515 
516 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) {
517   const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable",
518                         "-menable-unsafe-fp-math", "-freciprocal-math"};
519 
520   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
521 
522   ASSERT_FALSE(Diags->hasErrorOccurred());
523   ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
524   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
525   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
526   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
527 
528   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
529 
530   // Generated - explicitly provided.
531   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
532   // Not generated - implied by their generated parent.
533   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
534   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
535   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
536 }
537 
538 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) {
539   const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math",
540                         "-freciprocal-math"};
541 
542   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
543   ASSERT_FALSE(Diags->hasErrorOccurred());
544   ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
545   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
546   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
547   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
548 
549   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
550   // Not generated - missing.
551   ASSERT_THAT(GeneratedArgs,
552               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
553   // Generated - explicitly provided.
554   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
555   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
556   // Not generated - implied by its generated parent.
557   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
558 }
559 
560 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) {
561   const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"};
562 
563   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
564 
565   ASSERT_FALSE(Diags->hasErrorOccurred());
566 
567   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
568 
569   // Present options that were not implied are generated.
570   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
571   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
572 }
573 } // anonymous namespace
574