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/Basic/TargetOptions.h"
11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Frontend/TextDiagnosticBuffer.h"
13 #include "clang/Lex/PreprocessorOptions.h"
14 #include "clang/Serialization/ModuleFileExtension.h"
15 #include "llvm/Support/Host.h"
16
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19
20 using namespace llvm;
21 using namespace clang;
22
23 using ::testing::Contains;
24 using ::testing::HasSubstr;
25 using ::testing::StrEq;
26
27 namespace {
28 class CommandLineTest : public ::testing::Test {
29 public:
30 IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
31 SmallVector<const char *, 32> GeneratedArgs;
32 SmallVector<std::string, 32> GeneratedArgsStorage;
33 CompilerInvocation Invocation;
34
operator ()(const Twine & Arg)35 const char *operator()(const Twine &Arg) {
36 return GeneratedArgsStorage.emplace_back(Arg.str()).c_str();
37 }
38
CommandLineTest()39 CommandLineTest()
40 : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions(),
41 new TextDiagnosticBuffer())) {
42 }
43 };
44
45 template <typename M>
describeContainsN(M InnerMatcher,unsigned N,bool Negation)46 std::string describeContainsN(M InnerMatcher, unsigned N, bool Negation) {
47 StringRef Contains = Negation ? "doesn't contain" : "contains";
48 StringRef Instance = N == 1 ? " instance " : " instances ";
49 StringRef Element = "of element that ";
50
51 std::ostringstream Inner;
52 InnerMatcher.impl().DescribeTo(&Inner);
53
54 return (Contains + " exactly " + Twine(N) + Instance + Element + Inner.str())
55 .str();
56 }
57
MATCHER_P2(ContainsN,InnerMatcher,N,describeContainsN (InnerMatcher,N,negation))58 MATCHER_P2(ContainsN, InnerMatcher, N,
59 describeContainsN(InnerMatcher, N, negation)) {
60 auto InnerMatches = [this](const auto &Element) {
61 ::testing::internal::DummyMatchResultListener InnerListener;
62 return InnerMatcher.impl().MatchAndExplain(Element, &InnerListener);
63 };
64
65 return count_if(arg, InnerMatches) == N;
66 }
67
TEST(ContainsN,Empty)68 TEST(ContainsN, Empty) {
69 const char *Array[] = {""};
70
71 ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
72 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
73 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
74 }
75
TEST(ContainsN,Zero)76 TEST(ContainsN, Zero) {
77 const char *Array[] = {"y"};
78
79 ASSERT_THAT(Array, ContainsN(StrEq("x"), 0));
80 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
81 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
82 }
83
TEST(ContainsN,One)84 TEST(ContainsN, One) {
85 const char *Array[] = {"a", "b", "x", "z"};
86
87 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
88 ASSERT_THAT(Array, ContainsN(StrEq("x"), 1));
89 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2)));
90 }
91
TEST(ContainsN,Two)92 TEST(ContainsN, Two) {
93 const char *Array[] = {"x", "a", "b", "x"};
94
95 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0)));
96 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1)));
97 ASSERT_THAT(Array, ContainsN(StrEq("x"), 2));
98 }
99
100 // Copy constructor/assignment perform deep copy of reference-counted pointers.
101
TEST(CompilerInvocationTest,DeepCopyConstructor)102 TEST(CompilerInvocationTest, DeepCopyConstructor) {
103 CompilerInvocation A;
104 A.getAnalyzerOpts()->Config["Key"] = "Old";
105
106 CompilerInvocation B(A);
107 B.getAnalyzerOpts()->Config["Key"] = "New";
108
109 ASSERT_EQ(A.getAnalyzerOpts()->Config["Key"], "Old");
110 }
111
TEST(CompilerInvocationTest,DeepCopyAssignment)112 TEST(CompilerInvocationTest, DeepCopyAssignment) {
113 CompilerInvocation A;
114 A.getAnalyzerOpts()->Config["Key"] = "Old";
115
116 CompilerInvocation B;
117 B = A;
118 B.getAnalyzerOpts()->Config["Key"] = "New";
119
120 ASSERT_EQ(A.getAnalyzerOpts()->Config["Key"], "Old");
121 }
122
123 // Boolean option with a keypath that defaults to true.
124 // The only flag with a negative spelling can set the keypath to false.
125
TEST_F(CommandLineTest,BoolOptionDefaultTrueSingleFlagNotPresent)126 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) {
127 const char *Args[] = {""};
128
129 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
130 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
131
132 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
133
134 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file"))));
135 }
136
TEST_F(CommandLineTest,BoolOptionDefaultTrueSingleFlagPresent)137 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) {
138 const char *Args[] = {"-fno-temp-file"};
139
140 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
141 ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary);
142
143 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
144
145 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file")));
146 }
147
TEST_F(CommandLineTest,BoolOptionDefaultTrueSingleFlagUnknownPresent)148 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) {
149 const char *Args[] = {"-ftemp-file"};
150
151 // Driver-only flag.
152 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
153 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
154 }
155
156 // Boolean option with a keypath that defaults to true.
157 // The flag with negative spelling can set the keypath to false.
158 // The flag with positive spelling can reset the keypath to true.
159
TEST_F(CommandLineTest,BoolOptionDefaultTruePresentNone)160 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) {
161 const char *Args[] = {""};
162
163 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
164 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
165
166 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
167 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
168 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink"))));
169 }
170
TEST_F(CommandLineTest,BoolOptionDefaultTruePresentNegChange)171 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) {
172 const char *Args[] = {"-fno-autolink"};
173
174 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
175 ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink);
176
177 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
178 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink")));
179 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
180 }
181
TEST_F(CommandLineTest,BoolOptionDefaultTruePresentPosReset)182 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) {
183 const char *Args[] = {"-fautolink"};
184
185 // Driver-only flag.
186 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
187 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
188 }
189
190 // Boolean option with a keypath that defaults to false.
191 // The flag with negative spelling can set the keypath to true.
192 // The flag with positive spelling can reset the keypath to false.
193
TEST_F(CommandLineTest,BoolOptionDefaultFalsePresentNone)194 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) {
195 const char *Args[] = {""};
196
197 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
198 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
199
200 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
201 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
202 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables"))));
203 }
204
TEST_F(CommandLineTest,BoolOptionDefaultFalsePresentNegChange)205 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) {
206 const char *Args[] = {"-gno-inline-line-tables"};
207
208 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
209 ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables);
210
211 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
212 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables")));
213 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
214 }
215
TEST_F(CommandLineTest,BoolOptionDefaultFalsePresentPosReset)216 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) {
217 const char *Args[] = {"-ginline-line-tables"};
218
219 // Driver-only flag.
220 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
221 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
222 }
223
224 // Boolean option with a keypath that defaults to false.
225 // The flag with positive spelling can set the keypath to true.
226 // The flag with negative spelling can reset the keypath to false.
227
TEST_F(CommandLineTest,BoolOptionDefaultFalsePresentNoneX)228 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) {
229 const char *Args[] = {""};
230
231 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
232 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
233
234 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
235 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash"))));
236 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
237 }
238
TEST_F(CommandLineTest,BoolOptionDefaultFalsePresentPosChange)239 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) {
240 const char *Args[] = {"-gcodeview-ghash"};
241
242 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
243 ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash);
244
245 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
246 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash")));
247 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
248 }
249
TEST_F(CommandLineTest,BoolOptionDefaultFalsePresentNegReset)250 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) {
251 const char *Args[] = {"-gno-codeview-ghash"};
252
253 // Driver-only flag.
254 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
255 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
256 }
257
258 // Boolean option with a keypath that defaults to an arbitrary expression.
259 // The flag with positive spelling can set the keypath to true.
260 // The flag with negative spelling can set the keypath to false.
261
TEST_F(CommandLineTest,BoolOptionDefaultArbitraryTwoFlagsPresentNone)262 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) {
263 const char *Args = {""};
264
265 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
266 ASSERT_EQ(Invocation.getCodeGenOpts().ClearASTBeforeBackend, false);
267
268 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
269
270 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-no-clear-ast-before-backend"))));
271 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-clear-ast-before-backend"))));
272 }
273
TEST_F(CommandLineTest,BoolOptionDefaultArbitraryTwoFlagsPresentChange)274 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) {
275 const char *Args[] = {"-clear-ast-before-backend"};
276
277 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
278 ASSERT_EQ(Invocation.getCodeGenOpts().ClearASTBeforeBackend, true);
279
280 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
281 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-clear-ast-before-backend")));
282 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-no-clear-ast-before-backend"))));
283 }
284
TEST_F(CommandLineTest,BoolOptionDefaultArbitraryTwoFlagsPresentReset)285 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) {
286 const char *Args[] = {"-no-clear-ast-before-backend"};
287
288 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
289 ASSERT_EQ(Invocation.getCodeGenOpts().ClearASTBeforeBackend, false);
290
291 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
292 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-no-clear-ast-before-backend"))));
293 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-clear-ast-before-backend"))));
294 }
295
296 // Boolean option that gets the CC1Option flag from a let statement (which
297 // is applied **after** the record is defined):
298 //
299 // let Flags = [CC1Option] in {
300 // defm option : BoolOption<...>;
301 // }
302
TEST_F(CommandLineTest,BoolOptionCC1ViaLetPresentNone)303 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) {
304 const char *Args[] = {""};
305
306 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
307 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
308
309 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
310
311 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
312 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
313 }
314
TEST_F(CommandLineTest,BoolOptionCC1ViaLetPresentPos)315 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) {
316 const char *Args[] = {"-fdebug-pass-manager"};
317
318 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
319 ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager);
320
321 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
322
323 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fdebug-pass-manager"), 1));
324 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
325 }
326
TEST_F(CommandLineTest,BoolOptionCC1ViaLetPresentNeg)327 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) {
328 const char *Args[] = {"-fno-debug-pass-manager"};
329
330 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
331 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
332
333 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
334
335 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
336 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
337 }
338
TEST_F(CommandLineTest,CanGenerateCC1CommandLineFlag)339 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) {
340 const char *Args[] = {"-fmodules-strict-context-hash"};
341
342 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
343
344 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
345
346 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash")));
347 }
348
TEST_F(CommandLineTest,CanGenerateCC1CommandLineSeparate)349 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) {
350 const char *TripleCStr = "i686-apple-darwin9";
351 const char *Args[] = {"-triple", TripleCStr};
352
353 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
354
355 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
356
357 ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr)));
358 }
359
TEST_F(CommandLineTest,CanGenerateCC1CommandLineSeparateRequiredPresent)360 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredPresent) {
361 const std::string DefaultTriple =
362 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
363 const char *Args[] = {"-triple", DefaultTriple.c_str()};
364
365 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
366
367 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
368
369 // Triple should always be emitted even if it is the default
370 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
371 }
372
TEST_F(CommandLineTest,CanGenerateCC1CommandLineSeparateRequiredAbsent)373 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) {
374 const std::string DefaultTriple =
375 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
376 const char *Args[] = {""};
377
378 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
379
380 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
381
382 // Triple should always be emitted even if it is the default
383 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
384 }
385
TEST_F(CommandLineTest,SeparateEnumNonDefault)386 TEST_F(CommandLineTest, SeparateEnumNonDefault) {
387 const char *Args[] = {"-mrelocation-model", "static"};
388
389 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
390 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static);
391
392 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
393
394 // Non default relocation model.
395 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model")));
396 ASSERT_THAT(GeneratedArgs, Contains(StrEq("static")));
397 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static"))));
398 }
399
TEST_F(CommandLineTest,SeparateEnumDefault)400 TEST_F(CommandLineTest, SeparateEnumDefault) {
401 const char *Args[] = {"-mrelocation-model", "pic"};
402
403 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
404 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_);
405
406 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
407
408 // Default relocation model.
409 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model"))));
410 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic"))));
411 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic"))));
412 }
413
TEST_F(CommandLineTest,JoinedEnumNonDefault)414 TEST_F(CommandLineTest, JoinedEnumNonDefault) {
415 const char *Args[] = {"-fobjc-dispatch-method=non-legacy"};
416
417 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
418 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
419 CodeGenOptions::NonLegacy);
420
421 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
422
423 ASSERT_THAT(GeneratedArgs,
424 Contains(StrEq("-fobjc-dispatch-method=non-legacy")));
425 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
426 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy"))));
427 }
428
TEST_F(CommandLineTest,JoinedEnumDefault)429 TEST_F(CommandLineTest, JoinedEnumDefault) {
430 const char *Args[] = {"-fobjc-dispatch-method=legacy"};
431
432 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
433 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
434 CodeGenOptions::Legacy);
435
436 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
437
438 ASSERT_THAT(GeneratedArgs,
439 Not(Contains(StrEq("-fobjc-dispatch-method=legacy"))));
440 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
441 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
442 }
443
TEST_F(CommandLineTest,StringVectorEmpty)444 TEST_F(CommandLineTest, StringVectorEmpty) {
445 const char *Args[] = {""};
446
447 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
448 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
449
450 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
451
452 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file"))));
453 }
454
TEST_F(CommandLineTest,StringVectorSingle)455 TEST_F(CommandLineTest, StringVectorSingle) {
456 const char *Args[] = {"-fmodule-map-file=a"};
457
458 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
459 ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles,
460 std::vector<std::string>({"a"}));
461
462 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
463
464 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
465 ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 1));
466 }
467
TEST_F(CommandLineTest,StringVectorMultiple)468 TEST_F(CommandLineTest, StringVectorMultiple) {
469 const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"};
470
471 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
472 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles ==
473 std::vector<std::string>({"a", "b"}));
474
475 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
476
477 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
478 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=b"), 1));
479 ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 2));
480 }
481
482 // CommaJoined option with MarshallingInfoStringVector.
483
TEST_F(CommandLineTest,StringVectorCommaJoinedNone)484 TEST_F(CommandLineTest, StringVectorCommaJoinedNone) {
485 const char *Args[] = {""};
486
487 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
488 ASSERT_TRUE(Invocation.getLangOpts()->CommentOpts.BlockCommandNames.empty());
489
490 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
491
492 ASSERT_THAT(GeneratedArgs,
493 Not(Contains(HasSubstr("-fcomment-block-commands"))));
494 }
495
TEST_F(CommandLineTest,StringVectorCommaJoinedSingle)496 TEST_F(CommandLineTest, StringVectorCommaJoinedSingle) {
497 const char *Args[] = {"-fcomment-block-commands=x,y"};
498
499 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
500 ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames,
501 std::vector<std::string>({"x", "y"}));
502
503 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
504
505 ASSERT_THAT(GeneratedArgs,
506 ContainsN(StrEq("-fcomment-block-commands=x,y"), 1));
507 }
508
TEST_F(CommandLineTest,StringVectorCommaJoinedMultiple)509 TEST_F(CommandLineTest, StringVectorCommaJoinedMultiple) {
510 const char *Args[] = {"-fcomment-block-commands=x,y",
511 "-fcomment-block-commands=a,b"};
512
513 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
514 ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames,
515 std::vector<std::string>({"x", "y", "a", "b"}));
516
517 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
518
519 ASSERT_THAT(GeneratedArgs,
520 ContainsN(StrEq("-fcomment-block-commands=x,y,a,b"), 1));
521 }
522
523 // A flag that should be parsed only if a condition is met.
524
TEST_F(CommandLineTest,ConditionalParsingIfFalseFlagNotPresent)525 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagNotPresent) {
526 const char *Args[] = {""};
527
528 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
529
530 ASSERT_FALSE(Diags->hasErrorOccurred());
531 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsDevice);
532 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
533 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
534
535 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
536
537 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl"))));
538 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
539 }
540
TEST_F(CommandLineTest,ConditionalParsingIfFalseFlagPresent)541 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagPresent) {
542 const char *Args[] = {"-sycl-std=2017"};
543
544 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
545
546 ASSERT_FALSE(Diags->hasErrorOccurred());
547 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsDevice);
548 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
549 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
550
551 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
552
553 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-device"))));
554 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
555 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
556 }
557
TEST_F(CommandLineTest,ConditionalParsingIfNonsenseSyclStdArg)558 TEST_F(CommandLineTest, ConditionalParsingIfNonsenseSyclStdArg) {
559 const char *Args[] = {"-fsycl-is-device", "-sycl-std=garbage"};
560
561 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
562
563 ASSERT_TRUE(Diags->hasErrorOccurred());
564 ASSERT_TRUE(Invocation.getLangOpts()->SYCLIsDevice);
565 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
566 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
567
568 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
569
570 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
571 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
572 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
573 }
574
TEST_F(CommandLineTest,ConditionalParsingIfOddSyclStdArg1)575 TEST_F(CommandLineTest, ConditionalParsingIfOddSyclStdArg1) {
576 const char *Args[] = {"-fsycl-is-device", "-sycl-std=121"};
577
578 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
579
580 ASSERT_FALSE(Diags->hasErrorOccurred());
581 ASSERT_TRUE(Invocation.getLangOpts()->SYCLIsDevice);
582 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
583 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017);
584
585 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
586
587 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
588 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
589 ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=2017")));
590 }
591
TEST_F(CommandLineTest,ConditionalParsingIfOddSyclStdArg2)592 TEST_F(CommandLineTest, ConditionalParsingIfOddSyclStdArg2) {
593 const char *Args[] = {"-fsycl-is-device", "-sycl-std=1.2.1"};
594
595 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
596
597 ASSERT_FALSE(Diags->hasErrorOccurred());
598 ASSERT_TRUE(Invocation.getLangOpts()->SYCLIsDevice);
599 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
600 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017);
601
602 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
603
604 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
605 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
606 ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=2017")));
607 }
608
TEST_F(CommandLineTest,ConditionalParsingIfOddSyclStdArg3)609 TEST_F(CommandLineTest, ConditionalParsingIfOddSyclStdArg3) {
610 const char *Args[] = {"-fsycl-is-device", "-sycl-std=sycl-1.2.1"};
611
612 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
613
614 ASSERT_FALSE(Diags->hasErrorOccurred());
615 ASSERT_TRUE(Invocation.getLangOpts()->SYCLIsDevice);
616 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
617 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017);
618
619 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
620
621 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
622 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
623 ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=2017")));
624 }
625
TEST_F(CommandLineTest,ConditionalParsingIfTrueFlagNotPresentHost)626 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresentHost) {
627 const char *Args[] = {"-fsycl-is-host"};
628
629 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
630
631 ASSERT_FALSE(Diags->hasErrorOccurred());
632 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(),
633 LangOptions::SYCL_Default);
634
635 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
636
637 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-host")));
638 ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=")));
639 }
640
TEST_F(CommandLineTest,ConditionalParsingIfTrueFlagNotPresentDevice)641 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresentDevice) {
642 const char *Args[] = {"-fsycl-is-device"};
643
644 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
645
646 ASSERT_FALSE(Diags->hasErrorOccurred());
647 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(),
648 LangOptions::SYCL_Default);
649
650 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
651
652 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
653 ASSERT_THAT(GeneratedArgs, Contains(HasSubstr("-sycl-std=")));
654 }
655
TEST_F(CommandLineTest,ConditionalParsingIfTrueFlagPresent)656 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagPresent) {
657 const char *Args[] = {"-fsycl-is-device", "-sycl-std=2017"};
658
659 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
660
661 ASSERT_FALSE(Diags->hasErrorOccurred());
662 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017);
663
664 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
665
666 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
667 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-sycl-std=2017")));
668 }
669
670 // Wide integer option.
671
TEST_F(CommandLineTest,WideIntegerHighValue)672 TEST_F(CommandLineTest, WideIntegerHighValue) {
673 const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"};
674
675 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
676
677 ASSERT_FALSE(Diags->hasErrorOccurred());
678 ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp,
679 1609827494445723662ull);
680 }
681
682 // Tree of boolean options that can be (directly or transitively) implied by
683 // their parent:
684 //
685 // * -cl-unsafe-math-optimizations
686 // * -cl-mad-enable
687 // * -menable-unsafe-fp-math
688 // * -freciprocal-math
689
TEST_F(CommandLineTest,ImpliedBoolOptionsNoFlagPresent)690 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) {
691 const char *Args[] = {""};
692
693 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
694 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
695 ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
696 ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath);
697 ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip);
698
699 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
700
701 // Not generated - missing.
702 ASSERT_THAT(GeneratedArgs,
703 Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
704 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
705 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
706 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
707 }
708
TEST_F(CommandLineTest,ImpliedBoolOptionsRootFlagPresent)709 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) {
710 const char *Args[] = {"-cl-unsafe-math-optimizations"};
711
712 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
713 // Explicitly provided root flag.
714 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
715 // Directly implied by explicitly provided root flag.
716 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
717 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
718 // Transitively implied by explicitly provided root flag.
719 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
720
721 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
722
723 // Generated - explicitly provided.
724 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
725 // Not generated - implied by the generated root flag.
726 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
727 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
728 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
729 }
730
TEST_F(CommandLineTest,ImpliedBoolOptionsAllFlagsPresent)731 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) {
732 const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable",
733 "-menable-unsafe-fp-math", "-freciprocal-math"};
734
735 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
736 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
737 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
738 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
739 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
740
741 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
742
743 // Generated - explicitly provided.
744 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
745 // Not generated - implied by their generated parent.
746 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
747 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
748 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
749 }
750
TEST_F(CommandLineTest,ImpliedBoolOptionsImpliedFlagsPresent)751 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) {
752 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math",
753 "-freciprocal-math"};
754
755 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
756 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
757 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
758 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
759 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
760
761 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
762 // Not generated - missing.
763 ASSERT_THAT(GeneratedArgs,
764 Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
765 // Generated - explicitly provided.
766 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
767 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
768 // Not generated - implied by its generated parent.
769 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
770 }
771
TEST_F(CommandLineTest,PresentAndNotImpliedGenerated)772 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) {
773 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"};
774
775 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
776
777 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
778
779 // Present options that were not implied are generated.
780 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
781 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
782 }
783
784 // Diagnostic option.
785
TEST_F(CommandLineTest,DiagnosticOptionPresent)786 TEST_F(CommandLineTest, DiagnosticOptionPresent) {
787 const char *Args[] = {"-verify=xyz"};
788
789 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
790
791 ASSERT_EQ(Invocation.getDiagnosticOpts().VerifyPrefixes,
792 std::vector<std::string>({"xyz"}));
793
794 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
795
796 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-verify=xyz"), 1));
797 }
798
799 // Option default depends on language standard.
800
TEST_F(CommandLineTest,DigraphsImplied)801 TEST_F(CommandLineTest, DigraphsImplied) {
802 const char *Args[] = {""};
803
804 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
805 ASSERT_TRUE(Invocation.getLangOpts()->Digraphs);
806
807 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
808 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs"))));
809 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
810 }
811
TEST_F(CommandLineTest,DigraphsDisabled)812 TEST_F(CommandLineTest, DigraphsDisabled) {
813 const char *Args[] = {"-fno-digraphs"};
814
815 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
816 ASSERT_FALSE(Invocation.getLangOpts()->Digraphs);
817
818 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
819 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-digraphs")));
820 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
821 }
822
TEST_F(CommandLineTest,DigraphsNotImplied)823 TEST_F(CommandLineTest, DigraphsNotImplied) {
824 const char *Args[] = {"-std=c89"};
825
826 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
827 ASSERT_FALSE(Invocation.getLangOpts()->Digraphs);
828
829 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
830 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs"))));
831 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
832 }
833
TEST_F(CommandLineTest,DigraphsEnabled)834 TEST_F(CommandLineTest, DigraphsEnabled) {
835 const char *Args[] = {"-std=c89", "-fdigraphs"};
836
837 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
838 ASSERT_TRUE(Invocation.getLangOpts()->Digraphs);
839
840 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
841 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fdigraphs")));
842 }
843
844 struct DummyModuleFileExtension
845 : public llvm::RTTIExtends<DummyModuleFileExtension, ModuleFileExtension> {
846 static char ID;
847
getExtensionMetadata__anon91b32dea0111::DummyModuleFileExtension848 ModuleFileExtensionMetadata getExtensionMetadata() const override {
849 return {};
850 };
851
hashExtension__anon91b32dea0111::DummyModuleFileExtension852 void hashExtension(ExtensionHashBuilder &HBuilder) const override {}
853
854 std::unique_ptr<ModuleFileExtensionWriter>
createExtensionWriter__anon91b32dea0111::DummyModuleFileExtension855 createExtensionWriter(ASTWriter &Writer) override {
856 return {};
857 }
858
859 std::unique_ptr<ModuleFileExtensionReader>
createExtensionReader__anon91b32dea0111::DummyModuleFileExtension860 createExtensionReader(const ModuleFileExtensionMetadata &Metadata,
861 ASTReader &Reader, serialization::ModuleFile &Mod,
862 const llvm::BitstreamCursor &Stream) override {
863 return {};
864 }
865 };
866
867 char DummyModuleFileExtension::ID = 0;
868
TEST_F(CommandLineTest,TestModuleFileExtension)869 TEST_F(CommandLineTest, TestModuleFileExtension) {
870 const char *Args[] = {"-ftest-module-file-extension=first:2:1:0:first",
871 "-ftest-module-file-extension=second:3:2:1:second"};
872
873 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
874 ASSERT_THAT(Invocation.getFrontendOpts().ModuleFileExtensions.size(), 2);
875
876 // Exercise the check that only serializes instances of
877 // TestModuleFileExtension by providing an instance of another
878 // ModuleFileExtension subclass.
879 Invocation.getFrontendOpts().ModuleFileExtensions.push_back(
880 std::make_shared<DummyModuleFileExtension>());
881
882 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
883
884 ASSERT_THAT(GeneratedArgs,
885 ContainsN(HasSubstr("-ftest-module-file-extension="), 2));
886 ASSERT_THAT(
887 GeneratedArgs,
888 Contains(StrEq("-ftest-module-file-extension=first:2:1:0:first")));
889 ASSERT_THAT(
890 GeneratedArgs,
891 Contains(StrEq("-ftest-module-file-extension=second:3:2:1:second")));
892 }
893
TEST_F(CommandLineTest,RoundTrip)894 TEST_F(CommandLineTest, RoundTrip) {
895 // Testing one marshalled and one manually generated option from each
896 // CompilerInvocation member.
897 const char *Args[] = {
898 "-round-trip-args",
899 // LanguageOptions
900 "-std=c17",
901 "-fmax-tokens=10",
902 // TargetOptions
903 "-target-sdk-version=1.2.3",
904 "-meabi",
905 "4",
906 // DiagnosticOptions
907 "-Wundef-prefix=XY",
908 "-fdiagnostics-format",
909 "clang",
910 // HeaderSearchOptions
911 "-stdlib=libc++",
912 "-fimplicit-module-maps",
913 // PreprocessorOptions
914 "-DXY=AB",
915 "-include-pch",
916 "a.pch",
917 // AnalyzerOptions
918 "-analyzer-config",
919 "ctu-import-threshold=42",
920 "-unoptimized-cfg",
921 // MigratorOptions (no manually handled arguments)
922 "-no-ns-alloc-error",
923 // CodeGenOptions
924 "-debug-info-kind=limited",
925 "-debug-info-macro",
926 // DependencyOutputOptions
927 "--show-includes",
928 "-H",
929 // FileSystemOptions (no manually handled arguments)
930 "-working-directory",
931 "folder",
932 // FrontendOptions
933 "-load",
934 "plugin",
935 "-ast-merge",
936 // PreprocessorOutputOptions
937 "-dD",
938 "-CC",
939 };
940
941 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
942
943 ASSERT_TRUE(Invocation.getLangOpts()->C17);
944 ASSERT_EQ(Invocation.getLangOpts()->MaxTokens, 10u);
945
946 ASSERT_EQ(Invocation.getTargetOpts().SDKVersion, llvm::VersionTuple(1, 2, 3));
947 ASSERT_EQ(Invocation.getTargetOpts().EABIVersion, EABI::EABI4);
948
949 ASSERT_THAT(Invocation.getDiagnosticOpts().UndefPrefixes,
950 Contains(StrEq("XY")));
951 ASSERT_EQ(Invocation.getDiagnosticOpts().getFormat(),
952 TextDiagnosticFormat::Clang);
953
954 ASSERT_TRUE(Invocation.getHeaderSearchOpts().UseLibcxx);
955 ASSERT_TRUE(Invocation.getHeaderSearchOpts().ImplicitModuleMaps);
956
957 ASSERT_THAT(Invocation.getPreprocessorOpts().Macros,
958 Contains(std::make_pair(std::string("XY=AB"), false)));
959 ASSERT_EQ(Invocation.getPreprocessorOpts().ImplicitPCHInclude, "a.pch");
960
961 ASSERT_EQ(Invocation.getAnalyzerOpts()->Config["ctu-import-threshold"], "42");
962 ASSERT_TRUE(Invocation.getAnalyzerOpts()->UnoptimizedCFG);
963
964 ASSERT_TRUE(Invocation.getMigratorOpts().NoNSAllocReallocError);
965
966 ASSERT_EQ(Invocation.getCodeGenOpts().getDebugInfo(),
967 codegenoptions::DebugInfoKind::LimitedDebugInfo);
968 ASSERT_TRUE(Invocation.getCodeGenOpts().MacroDebugInfo);
969
970 ASSERT_EQ(Invocation.getDependencyOutputOpts().ShowIncludesDest,
971 ShowIncludesDestination::Stdout);
972 ASSERT_TRUE(Invocation.getDependencyOutputOpts().ShowHeaderIncludes);
973 }
974
TEST_F(CommandLineTest,PluginArgsRoundTripDeterminism)975 TEST_F(CommandLineTest, PluginArgsRoundTripDeterminism) {
976 const char *Args[] = {
977 "-plugin-arg-blink-gc-plugin", "no-members-in-stack-allocated",
978 "-plugin-arg-find-bad-constructs", "checked-ptr-as-trivial-member",
979 "-plugin-arg-find-bad-constructs", "check-ipc",
980 // Enable round-trip to ensure '-plugin-arg' generation is deterministic.
981 "-round-trip-args"};
982
983 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
984 }
985 } // anonymous namespace
986