xref: /llvm-project/clang/unittests/Frontend/CompilerInvocationTest.cpp (revision 63a24816f561a5d8e28ca7054892bd8602618be4)
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 // Tree of boolean options that can be (directly or transitively) implied by
452 // their parent:
453 //
454 //   * -cl-unsafe-math-optimizations
455 //     * -cl-mad-enable
456 //     * -menable-unsafe-fp-math
457 //       * -freciprocal-math
458 
459 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) {
460   const char *Args[] = {""};
461 
462   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
463 
464   ASSERT_FALSE(Diags->hasErrorOccurred());
465   ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
466   ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
467   ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath);
468   ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip);
469 
470   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
471 
472   // Not generated - missing.
473   ASSERT_THAT(GeneratedArgs,
474               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
475   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
476   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
477   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
478 }
479 
480 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) {
481   const char *Args[] = {"-cl-unsafe-math-optimizations"};
482 
483   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
484 
485   ASSERT_FALSE(Diags->hasErrorOccurred());
486   // Explicitly provided root flag.
487   ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
488   // Directly implied by explicitly provided root flag.
489   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
490   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
491   // Transitively implied by explicitly provided root flag.
492   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
493 
494   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
495 
496   // Generated - explicitly provided.
497   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
498   // Not generated - implied by the generated root flag.
499   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
500   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
501   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
502 }
503 
504 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) {
505   const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable",
506                         "-menable-unsafe-fp-math", "-freciprocal-math"};
507 
508   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
509 
510   ASSERT_FALSE(Diags->hasErrorOccurred());
511   ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
512   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
513   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
514   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
515 
516   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
517 
518   // Generated - explicitly provided.
519   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
520   // Not generated - implied by their generated parent.
521   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
522   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
523   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
524 }
525 
526 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) {
527   const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math",
528                         "-freciprocal-math"};
529 
530   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
531   ASSERT_FALSE(Diags->hasErrorOccurred());
532   ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
533   ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
534   ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
535   ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
536 
537   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
538   // Not generated - missing.
539   ASSERT_THAT(GeneratedArgs,
540               Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
541   // Generated - explicitly provided.
542   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
543   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
544   // Not generated - implied by its generated parent.
545   ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
546 }
547 
548 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) {
549   const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"};
550 
551   CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
552 
553   ASSERT_FALSE(Diags->hasErrorOccurred());
554 
555   Invocation.generateCC1CommandLine(GeneratedArgs, *this);
556 
557   // Present options that were not implied are generated.
558   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
559   ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
560 }
561 } // anonymous namespace
562