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