[SCCP] Avoid modifying AdditionalUsers while iterating over it
[llvm-project.git] / clang / unittests / Frontend / CompilerInvocationTest.cpp
blobb846e6ead28c91bcab86cf34f8a54f0509704c79
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 //===----------------------------------------------------------------------===//
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"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
20 using namespace llvm;
21 using namespace clang;
23 using ::testing::Contains;
24 using ::testing::HasSubstr;
25 using ::testing::StrEq;
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;
35 const char *operator()(const Twine &Arg) {
36 return GeneratedArgsStorage.emplace_back(Arg.str()).c_str();
39 CommandLineTest()
40 : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions(),
41 new TextDiagnosticBuffer())) {
45 template <typename M>
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 ";
51 std::ostringstream Inner;
52 InnerMatcher.impl().DescribeTo(&Inner);
54 return (Contains + " exactly " + Twine(N) + Instance + Element + Inner.str())
55 .str();
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);
65 return count_if(arg, InnerMatches) == N;
68 TEST(ContainsN, Empty) {
69 const char *Array[] = {""};
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)));
76 TEST(ContainsN, Zero) {
77 const char *Array[] = {"y"};
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)));
84 TEST(ContainsN, One) {
85 const char *Array[] = {"a", "b", "x", "z"};
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)));
92 TEST(ContainsN, Two) {
93 const char *Array[] = {"x", "a", "b", "x"};
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));
100 // Boolean option with a keypath that defaults to true.
101 // The only flag with a negative spelling can set the keypath to false.
103 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) {
104 const char *Args[] = {""};
106 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
107 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
109 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
111 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file"))));
114 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) {
115 const char *Args[] = {"-fno-temp-file"};
117 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
118 ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary);
120 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
122 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file")));
125 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) {
126 const char *Args[] = {"-ftemp-file"};
128 // Driver-only flag.
129 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
130 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary);
133 // Boolean option with a keypath that defaults to true.
134 // The flag with negative spelling can set the keypath to false.
135 // The flag with positive spelling can reset the keypath to true.
137 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) {
138 const char *Args[] = {""};
140 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
141 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
143 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
144 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
145 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink"))));
148 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) {
149 const char *Args[] = {"-fno-autolink"};
151 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
152 ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink);
154 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
155 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink")));
156 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink"))));
159 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) {
160 const char *Args[] = {"-fautolink"};
162 // Driver-only flag.
163 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
164 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink);
167 // Boolean option with a keypath that defaults to false.
168 // The flag with negative spelling can set the keypath to true.
169 // The flag with positive spelling can reset the keypath to false.
171 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) {
172 const char *Args[] = {""};
174 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
175 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
177 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
178 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
179 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables"))));
182 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) {
183 const char *Args[] = {"-gno-inline-line-tables"};
185 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
186 ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables);
188 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
189 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables")));
190 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables"))));
193 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) {
194 const char *Args[] = {"-ginline-line-tables"};
196 // Driver-only flag.
197 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
198 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables);
201 // Boolean option with a keypath that defaults to false.
202 // The flag with positive spelling can set the keypath to true.
203 // The flag with negative spelling can reset the keypath to false.
205 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) {
206 const char *Args[] = {""};
208 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
209 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
211 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
212 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash"))));
213 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
216 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) {
217 const char *Args[] = {"-gcodeview-ghash"};
219 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
220 ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash);
222 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
223 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash")));
224 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash"))));
227 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) {
228 const char *Args[] = {"-gno-codeview-ghash"};
230 // Driver-only flag.
231 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
232 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash);
235 // Boolean option with a keypath that defaults to an arbitrary expression.
236 // The flag with positive spelling can set the keypath to true.
237 // The flag with negative spelling can set the keypath to false.
239 static constexpr unsigned PassManagerDefault =
240 !static_cast<unsigned>(LLVM_ENABLE_NEW_PASS_MANAGER);
242 static constexpr const char *PassManagerResetByFlag =
243 LLVM_ENABLE_NEW_PASS_MANAGER ? "-fno-legacy-pass-manager"
244 : "-flegacy-pass-manager";
246 static constexpr const char *PassManagerChangedByFlag =
247 LLVM_ENABLE_NEW_PASS_MANAGER ? "-flegacy-pass-manager"
248 : "-fno-legacy-pass-manager";
250 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) {
251 const char *Args = {""};
253 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
254 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault);
256 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
258 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
259 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag))));
262 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) {
263 const char *Args[] = {PassManagerChangedByFlag};
265 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
266 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, !PassManagerDefault);
268 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
269 ASSERT_THAT(GeneratedArgs, Contains(StrEq(PassManagerChangedByFlag)));
270 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
273 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) {
274 const char *Args[] = {PassManagerResetByFlag};
276 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
277 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault);
279 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
280 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag))));
281 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag))));
284 // Boolean option that gets the CC1Option flag from a let statement (which
285 // is applied **after** the record is defined):
287 // let Flags = [CC1Option] in {
288 // defm option : BoolOption<...>;
289 // }
291 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) {
292 const char *Args[] = {""};
294 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
295 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
297 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
299 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
300 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
303 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) {
304 const char *Args[] = {"-fdebug-pass-manager"};
306 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
307 ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager);
309 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
311 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fdebug-pass-manager"), 1));
312 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
315 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) {
316 const char *Args[] = {"-fno-debug-pass-manager"};
318 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
319 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager);
321 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
323 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager"))));
324 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager"))));
327 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) {
328 const char *Args[] = {"-fmodules-strict-context-hash"};
330 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
332 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
334 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash")));
337 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) {
338 const char *TripleCStr = "i686-apple-darwin9";
339 const char *Args[] = {"-triple", TripleCStr};
341 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
343 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
345 ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr)));
348 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredPresent) {
349 const std::string DefaultTriple =
350 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
351 const char *Args[] = {"-triple", DefaultTriple.c_str()};
353 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
355 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
357 // Triple should always be emitted even if it is the default
358 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
361 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) {
362 const std::string DefaultTriple =
363 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
364 const char *Args[] = {""};
366 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
368 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
370 // Triple should always be emitted even if it is the default
371 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str())));
374 TEST_F(CommandLineTest, SeparateEnumNonDefault) {
375 const char *Args[] = {"-mrelocation-model", "static"};
377 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
378 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static);
380 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
382 // Non default relocation model.
383 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model")));
384 ASSERT_THAT(GeneratedArgs, Contains(StrEq("static")));
385 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static"))));
388 TEST_F(CommandLineTest, SeparateEnumDefault) {
389 const char *Args[] = {"-mrelocation-model", "pic"};
391 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
392 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_);
394 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
396 // Default relocation model.
397 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model"))));
398 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic"))));
399 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic"))));
402 TEST_F(CommandLineTest, JoinedEnumNonDefault) {
403 const char *Args[] = {"-fobjc-dispatch-method=non-legacy"};
405 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
406 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
407 CodeGenOptions::NonLegacy);
409 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
411 ASSERT_THAT(GeneratedArgs,
412 Contains(StrEq("-fobjc-dispatch-method=non-legacy")));
413 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
414 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy"))));
417 TEST_F(CommandLineTest, JoinedEnumDefault) {
418 const char *Args[] = {"-fobjc-dispatch-method=legacy"};
420 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
421 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(),
422 CodeGenOptions::Legacy);
424 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
426 ASSERT_THAT(GeneratedArgs,
427 Not(Contains(StrEq("-fobjc-dispatch-method=legacy"))));
428 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method="))));
429 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy"))));
432 TEST_F(CommandLineTest, StringVectorEmpty) {
433 const char *Args[] = {""};
435 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
436 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty());
438 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
440 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file"))));
443 TEST_F(CommandLineTest, StringVectorSingle) {
444 const char *Args[] = {"-fmodule-map-file=a"};
446 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
447 ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles,
448 std::vector<std::string>({"a"}));
450 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
452 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
453 ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 1));
456 TEST_F(CommandLineTest, StringVectorMultiple) {
457 const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"};
459 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
460 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles ==
461 std::vector<std::string>({"a", "b"}));
463 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
465 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1));
466 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=b"), 1));
467 ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 2));
470 // CommaJoined option with MarshallingInfoStringVector.
472 TEST_F(CommandLineTest, StringVectorCommaJoinedNone) {
473 const char *Args[] = {""};
475 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
476 ASSERT_TRUE(Invocation.getLangOpts()->CommentOpts.BlockCommandNames.empty());
478 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
480 ASSERT_THAT(GeneratedArgs,
481 Not(Contains(HasSubstr("-fcomment-block-commands"))));
484 TEST_F(CommandLineTest, StringVectorCommaJoinedSingle) {
485 const char *Args[] = {"-fcomment-block-commands=x,y"};
487 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
488 ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames,
489 std::vector<std::string>({"x", "y"}));
491 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
493 ASSERT_THAT(GeneratedArgs,
494 ContainsN(StrEq("-fcomment-block-commands=x,y"), 1));
497 TEST_F(CommandLineTest, StringVectorCommaJoinedMultiple) {
498 const char *Args[] = {"-fcomment-block-commands=x,y",
499 "-fcomment-block-commands=a,b"};
501 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
502 ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames,
503 std::vector<std::string>({"x", "y", "a", "b"}));
505 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
507 ASSERT_THAT(GeneratedArgs,
508 ContainsN(StrEq("-fcomment-block-commands=x,y,a,b"), 1));
511 // A flag that should be parsed only if a condition is met.
513 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagNotPresent) {
514 const char *Args[] = {""};
516 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
518 ASSERT_FALSE(Diags->hasErrorOccurred());
519 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsDevice);
520 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
521 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
523 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
525 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl"))));
526 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
529 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagPresent) {
530 const char *Args[] = {"-sycl-std=2017"};
532 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
534 ASSERT_FALSE(Diags->hasErrorOccurred());
535 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsDevice);
536 ASSERT_FALSE(Invocation.getLangOpts()->SYCLIsHost);
537 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
539 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
541 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-device"))));
542 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl-is-host"))));
543 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
546 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresent) {
547 const char *Args[] = {"-fsycl-is-host"};
549 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
551 ASSERT_FALSE(Diags->hasErrorOccurred());
552 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None);
554 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
556 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-host")));
557 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std="))));
560 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagPresent) {
561 const char *Args[] = {"-fsycl-is-device", "-sycl-std=2017"};
563 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
565 ASSERT_FALSE(Diags->hasErrorOccurred());
566 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017);
568 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
570 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl-is-device")));
571 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-sycl-std=2017")));
574 // Wide integer option.
576 TEST_F(CommandLineTest, WideIntegerHighValue) {
577 const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"};
579 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags);
581 ASSERT_FALSE(Diags->hasErrorOccurred());
582 ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp,
583 1609827494445723662ull);
586 // Tree of boolean options that can be (directly or transitively) implied by
587 // their parent:
589 // * -cl-unsafe-math-optimizations
590 // * -cl-mad-enable
591 // * -menable-unsafe-fp-math
592 // * -freciprocal-math
594 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) {
595 const char *Args[] = {""};
597 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
598 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
599 ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
600 ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath);
601 ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip);
603 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
605 // Not generated - missing.
606 ASSERT_THAT(GeneratedArgs,
607 Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
608 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
609 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
610 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
613 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) {
614 const char *Args[] = {"-cl-unsafe-math-optimizations"};
616 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
617 // Explicitly provided root flag.
618 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
619 // Directly implied by explicitly provided root flag.
620 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
621 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
622 // Transitively implied by explicitly provided root flag.
623 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
625 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
627 // Generated - explicitly provided.
628 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
629 // Not generated - implied by the generated root flag.
630 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
631 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
632 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
635 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) {
636 const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable",
637 "-menable-unsafe-fp-math", "-freciprocal-math"};
639 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
640 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath);
641 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
642 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
643 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
645 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
647 // Generated - explicitly provided.
648 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations")));
649 // Not generated - implied by their generated parent.
650 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable"))));
651 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math"))));
652 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
655 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) {
656 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math",
657 "-freciprocal-math"};
659 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
660 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath);
661 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD);
662 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath);
663 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip);
665 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
666 // Not generated - missing.
667 ASSERT_THAT(GeneratedArgs,
668 Not(Contains(StrEq("-cl-unsafe-math-optimizations"))));
669 // Generated - explicitly provided.
670 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
671 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
672 // Not generated - implied by its generated parent.
673 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math"))));
676 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) {
677 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"};
679 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
681 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
683 // Present options that were not implied are generated.
684 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable")));
685 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math")));
688 // Diagnostic option.
690 TEST_F(CommandLineTest, DiagnosticOptionPresent) {
691 const char *Args[] = {"-verify=xyz"};
693 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
695 ASSERT_EQ(Invocation.getDiagnosticOpts().VerifyPrefixes,
696 std::vector<std::string>({"xyz"}));
698 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
700 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-verify=xyz"), 1));
703 // Option default depends on language standard.
705 TEST_F(CommandLineTest, DigraphsImplied) {
706 const char *Args[] = {""};
708 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
709 ASSERT_TRUE(Invocation.getLangOpts()->Digraphs);
711 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
712 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs"))));
713 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
716 TEST_F(CommandLineTest, DigraphsDisabled) {
717 const char *Args[] = {"-fno-digraphs"};
719 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
720 ASSERT_FALSE(Invocation.getLangOpts()->Digraphs);
722 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
723 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-digraphs")));
724 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
727 TEST_F(CommandLineTest, DigraphsNotImplied) {
728 const char *Args[] = {"-std=c89"};
730 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
731 ASSERT_FALSE(Invocation.getLangOpts()->Digraphs);
733 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
734 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-digraphs"))));
735 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdigraphs"))));
738 TEST_F(CommandLineTest, DigraphsEnabled) {
739 const char *Args[] = {"-std=c89", "-fdigraphs"};
741 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
742 ASSERT_TRUE(Invocation.getLangOpts()->Digraphs);
744 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
745 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fdigraphs")));
748 struct DummyModuleFileExtension
749 : public llvm::RTTIExtends<DummyModuleFileExtension, ModuleFileExtension> {
750 static char ID;
752 ModuleFileExtensionMetadata getExtensionMetadata() const override {
753 return {};
756 llvm::hash_code hashExtension(llvm::hash_code Code) const override {
757 return {};
760 std::unique_ptr<ModuleFileExtensionWriter>
761 createExtensionWriter(ASTWriter &Writer) override {
762 return {};
765 std::unique_ptr<ModuleFileExtensionReader>
766 createExtensionReader(const ModuleFileExtensionMetadata &Metadata,
767 ASTReader &Reader, serialization::ModuleFile &Mod,
768 const llvm::BitstreamCursor &Stream) override {
769 return {};
773 char DummyModuleFileExtension::ID = 0;
775 TEST_F(CommandLineTest, TestModuleFileExtension) {
776 const char *Args[] = {"-ftest-module-file-extension=first:2:1:0:first",
777 "-ftest-module-file-extension=second:3:2:1:second"};
779 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
780 ASSERT_THAT(Invocation.getFrontendOpts().ModuleFileExtensions.size(), 2);
782 // Exercise the check that only serializes instances of
783 // TestModuleFileExtension by providing an instance of another
784 // ModuleFileExtension subclass.
785 Invocation.getFrontendOpts().ModuleFileExtensions.push_back(
786 std::make_shared<DummyModuleFileExtension>());
788 Invocation.generateCC1CommandLine(GeneratedArgs, *this);
790 ASSERT_THAT(GeneratedArgs,
791 ContainsN(HasSubstr("-ftest-module-file-extension="), 2));
792 ASSERT_THAT(
793 GeneratedArgs,
794 Contains(StrEq("-ftest-module-file-extension=first:2:1:0:first")));
795 ASSERT_THAT(
796 GeneratedArgs,
797 Contains(StrEq("-ftest-module-file-extension=second:3:2:1:second")));
800 TEST_F(CommandLineTest, RoundTrip) {
801 // Testing one marshalled and one manually generated option from each
802 // CompilerInvocation member.
803 const char *Args[] = {
804 "-round-trip-args",
805 // LanguageOptions
806 "-std=c17",
807 "-fmax-tokens=10",
808 // TargetOptions
809 "-target-sdk-version=1.2.3",
810 "-meabi",
811 "4",
812 // DiagnosticOptions
813 "-Wundef-prefix=XY",
814 "-fdiagnostics-format",
815 "clang",
816 // HeaderSearchOptions
817 "-stdlib=libc++",
818 "-fimplicit-module-maps",
819 // PreprocessorOptions
820 "-DXY=AB",
821 "-include-pch",
822 "a.pch",
823 // AnalyzerOptions
824 "-analyzer-config",
825 "ctu-import-threshold=42",
826 "-unoptimized-cfg",
827 // MigratorOptions (no manually handled arguments)
828 "-no-ns-alloc-error",
829 // CodeGenOptions
830 "-debug-info-kind=limited",
831 "-debug-info-macro",
832 // DependencyOutputOptions
833 "--show-includes",
834 "-H",
835 // FileSystemOptions (no manually handled arguments)
836 "-working-directory",
837 "folder",
838 // FrontendOptions
839 "-load",
840 "plugin",
841 "-ast-merge",
842 // PreprocessorOutputOptions
843 "-dD",
844 "-CC",
847 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags));
849 ASSERT_TRUE(Invocation.getLangOpts()->C17);
850 ASSERT_EQ(Invocation.getLangOpts()->MaxTokens, 10u);
852 ASSERT_EQ(Invocation.getTargetOpts().SDKVersion, llvm::VersionTuple(1, 2, 3));
853 ASSERT_EQ(Invocation.getTargetOpts().EABIVersion, EABI::EABI4);
855 ASSERT_THAT(Invocation.getDiagnosticOpts().UndefPrefixes,
856 Contains(StrEq("XY")));
857 ASSERT_EQ(Invocation.getDiagnosticOpts().getFormat(),
858 TextDiagnosticFormat::Clang);
860 ASSERT_TRUE(Invocation.getHeaderSearchOpts().UseLibcxx);
861 ASSERT_TRUE(Invocation.getHeaderSearchOpts().ImplicitModuleMaps);
863 ASSERT_THAT(Invocation.getPreprocessorOpts().Macros,
864 Contains(std::make_pair(std::string("XY=AB"), false)));
865 ASSERT_EQ(Invocation.getPreprocessorOpts().ImplicitPCHInclude, "a.pch");
867 ASSERT_EQ(Invocation.getAnalyzerOpts()->Config["ctu-import-threshold"], "42");
868 ASSERT_TRUE(Invocation.getAnalyzerOpts()->UnoptimizedCFG);
870 ASSERT_TRUE(Invocation.getMigratorOpts().NoNSAllocReallocError);
872 ASSERT_EQ(Invocation.getCodeGenOpts().getDebugInfo(),
873 codegenoptions::DebugInfoKind::LimitedDebugInfo);
874 ASSERT_TRUE(Invocation.getCodeGenOpts().MacroDebugInfo);
876 ASSERT_EQ(Invocation.getDependencyOutputOpts().ShowIncludesDest,
877 ShowIncludesDestination::Stdout);
878 ASSERT_TRUE(Invocation.getDependencyOutputOpts().ShowHeaderIncludes);
880 } // anonymous namespace