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 template <typename M> 43 std::string describeContainsN(M InnerMatcher, unsigned N, bool Negation) { 44 StringRef Contains = Negation ? "doesn't contain" : "contains"; 45 StringRef Instance = N == 1 ? " instance " : " instances "; 46 StringRef Element = "of element that "; 47 48 std::ostringstream Inner; 49 InnerMatcher.impl().DescribeTo(&Inner); 50 51 return (Contains + " exactly " + Twine(N) + Instance + Element + Inner.str()) 52 .str(); 53 } 54 55 MATCHER_P2(ContainsN, InnerMatcher, N, 56 describeContainsN(InnerMatcher, N, negation)) { 57 auto InnerMatches = [this](const auto &Element) { 58 ::testing::internal::DummyMatchResultListener InnerListener; 59 return InnerMatcher.impl().MatchAndExplain(Element, &InnerListener); 60 }; 61 62 return count_if(arg, InnerMatches) == N; 63 } 64 65 TEST(ContainsN, Empty) { 66 const char *Array[] = {""}; 67 68 ASSERT_THAT(Array, ContainsN(StrEq("x"), 0)); 69 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1))); 70 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2))); 71 } 72 73 TEST(ContainsN, Zero) { 74 const char *Array[] = {"y"}; 75 76 ASSERT_THAT(Array, ContainsN(StrEq("x"), 0)); 77 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1))); 78 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2))); 79 } 80 81 TEST(ContainsN, One) { 82 const char *Array[] = {"a", "b", "x", "z"}; 83 84 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0))); 85 ASSERT_THAT(Array, ContainsN(StrEq("x"), 1)); 86 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 2))); 87 } 88 89 TEST(ContainsN, Two) { 90 const char *Array[] = {"x", "a", "b", "x"}; 91 92 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 0))); 93 ASSERT_THAT(Array, Not(ContainsN(StrEq("x"), 1))); 94 ASSERT_THAT(Array, ContainsN(StrEq("x"), 2)); 95 } 96 97 // Boolean option with a keypath that defaults to true. 98 // The only flag with a negative spelling can set the keypath to false. 99 100 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) { 101 const char *Args[] = {""}; 102 103 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 104 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary); 105 106 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 107 108 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file")))); 109 } 110 111 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) { 112 const char *Args[] = {"-fno-temp-file"}; 113 114 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 115 ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary); 116 117 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 118 119 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); 120 } 121 122 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) { 123 const char *Args[] = {"-ftemp-file"}; 124 125 // Driver-only flag. 126 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 127 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary); 128 } 129 130 // Boolean option with a keypath that defaults to true. 131 // The flag with negative spelling can set the keypath to false. 132 // The flag with positive spelling can reset the keypath to true. 133 134 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) { 135 const char *Args[] = {""}; 136 137 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 138 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); 139 140 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 141 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink")))); 142 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink")))); 143 } 144 145 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) { 146 const char *Args[] = {"-fno-autolink"}; 147 148 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 149 ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink); 150 151 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 152 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink"))); 153 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink")))); 154 } 155 156 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) { 157 const char *Args[] = {"-fautolink"}; 158 159 // Driver-only flag. 160 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 161 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); 162 } 163 164 // Boolean option with a keypath that defaults to false. 165 // The flag with negative spelling can set the keypath to true. 166 // The flag with positive spelling can reset the keypath to false. 167 168 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) { 169 const char *Args[] = {""}; 170 171 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 172 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables); 173 174 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 175 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables")))); 176 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables")))); 177 } 178 179 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) { 180 const char *Args[] = {"-gno-inline-line-tables"}; 181 182 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 183 ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables); 184 185 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 186 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables"))); 187 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables")))); 188 } 189 190 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) { 191 const char *Args[] = {"-ginline-line-tables"}; 192 193 // Driver-only flag. 194 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 195 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables); 196 } 197 198 // Boolean option with a keypath that defaults to false. 199 // The flag with positive spelling can set the keypath to true. 200 // The flag with negative spelling can reset the keypath to false. 201 202 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) { 203 const char *Args[] = {""}; 204 205 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 206 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash); 207 208 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 209 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash")))); 210 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash")))); 211 } 212 213 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) { 214 const char *Args[] = {"-gcodeview-ghash"}; 215 216 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 217 ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash); 218 219 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 220 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash"))); 221 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash")))); 222 } 223 224 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) { 225 const char *Args[] = {"-gno-codeview-ghash"}; 226 227 // Driver-only flag. 228 ASSERT_FALSE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 229 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash); 230 } 231 232 // Boolean option with a keypath that defaults to an arbitrary expression. 233 // The flag with positive spelling can set the keypath to true. 234 // The flag with negative spelling can set the keypath to false. 235 236 static constexpr unsigned PassManagerDefault = 237 !static_cast<unsigned>(LLVM_ENABLE_NEW_PASS_MANAGER); 238 239 static constexpr const char *PassManagerResetByFlag = 240 LLVM_ENABLE_NEW_PASS_MANAGER ? "-fno-legacy-pass-manager" 241 : "-flegacy-pass-manager"; 242 243 static constexpr const char *PassManagerChangedByFlag = 244 LLVM_ENABLE_NEW_PASS_MANAGER ? "-flegacy-pass-manager" 245 : "-fno-legacy-pass-manager"; 246 247 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) { 248 const char *Args = {""}; 249 250 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 251 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault); 252 253 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 254 255 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag)))); 256 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag)))); 257 } 258 259 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) { 260 const char *Args[] = {PassManagerChangedByFlag}; 261 262 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 263 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, !PassManagerDefault); 264 265 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 266 ASSERT_THAT(GeneratedArgs, Contains(StrEq(PassManagerChangedByFlag))); 267 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag)))); 268 } 269 270 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) { 271 const char *Args[] = {PassManagerResetByFlag}; 272 273 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 274 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault); 275 276 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 277 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag)))); 278 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag)))); 279 } 280 281 // Boolean option that gets the CC1Option flag from a let statement (which 282 // is applied **after** the record is defined): 283 // 284 // let Flags = [CC1Option] in { 285 // defm option : BoolOption<...>; 286 // } 287 288 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) { 289 const char *Args[] = {""}; 290 291 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 292 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager); 293 294 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 295 296 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager")))); 297 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager")))); 298 } 299 300 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) { 301 const char *Args[] = {"-fdebug-pass-manager"}; 302 303 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 304 ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager); 305 306 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 307 308 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fdebug-pass-manager"), 1)); 309 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager")))); 310 } 311 312 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) { 313 const char *Args[] = {"-fno-debug-pass-manager"}; 314 315 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 316 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager); 317 318 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 319 320 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager")))); 321 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager")))); 322 } 323 324 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) { 325 const char *Args[] = {"-fmodules-strict-context-hash"}; 326 327 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 328 329 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 330 331 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash"))); 332 } 333 334 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) { 335 const char *TripleCStr = "i686-apple-darwin9"; 336 const char *Args[] = {"-triple", TripleCStr}; 337 338 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 339 340 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 341 342 ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr))); 343 } 344 345 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredPresent) { 346 const std::string DefaultTriple = 347 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 348 const char *Args[] = {"-triple", DefaultTriple.c_str()}; 349 350 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 351 352 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 353 354 // Triple should always be emitted even if it is the default 355 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 356 } 357 358 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) { 359 const std::string DefaultTriple = 360 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 361 const char *Args[] = {""}; 362 363 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 364 365 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 366 367 // Triple should always be emitted even if it is the default 368 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 369 } 370 371 TEST_F(CommandLineTest, SeparateEnumNonDefault) { 372 const char *Args[] = {"-mrelocation-model", "static"}; 373 374 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 375 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static); 376 377 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 378 379 // Non default relocation model. 380 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model"))); 381 ASSERT_THAT(GeneratedArgs, Contains(StrEq("static"))); 382 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static")))); 383 } 384 385 TEST_F(CommandLineTest, SeparateEnumDefault) { 386 const char *Args[] = {"-mrelocation-model", "pic"}; 387 388 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 389 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_); 390 391 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 392 393 // Default relocation model. 394 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model")))); 395 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic")))); 396 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic")))); 397 } 398 399 TEST_F(CommandLineTest, JoinedEnumNonDefault) { 400 const char *Args[] = {"-fobjc-dispatch-method=non-legacy"}; 401 402 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 403 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(), 404 CodeGenOptions::NonLegacy); 405 406 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 407 408 ASSERT_THAT(GeneratedArgs, 409 Contains(StrEq("-fobjc-dispatch-method=non-legacy"))); 410 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method=")))); 411 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy")))); 412 } 413 414 TEST_F(CommandLineTest, JoinedEnumDefault) { 415 const char *Args[] = {"-fobjc-dispatch-method=legacy"}; 416 417 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 418 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(), 419 CodeGenOptions::Legacy); 420 421 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 422 423 ASSERT_THAT(GeneratedArgs, 424 Not(Contains(StrEq("-fobjc-dispatch-method=legacy")))); 425 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method=")))); 426 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy")))); 427 } 428 429 TEST_F(CommandLineTest, StringVectorEmpty) { 430 const char *Args[] = {""}; 431 432 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 433 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty()); 434 435 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 436 437 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file")))); 438 } 439 440 TEST_F(CommandLineTest, StringVectorSingle) { 441 const char *Args[] = {"-fmodule-map-file=a"}; 442 443 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 444 ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles, 445 std::vector<std::string>({"a"})); 446 447 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 448 449 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1)); 450 ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 1)); 451 } 452 453 TEST_F(CommandLineTest, StringVectorMultiple) { 454 const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"}; 455 456 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 457 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles == 458 std::vector<std::string>({"a", "b"})); 459 460 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 461 462 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=a"), 1)); 463 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-fmodule-map-file=b"), 1)); 464 ASSERT_THAT(GeneratedArgs, ContainsN(HasSubstr("-fmodule-map-file"), 2)); 465 } 466 467 // CommaJoined option with MarshallingInfoStringVector. 468 469 TEST_F(CommandLineTest, StringVectorCommaJoinedNone) { 470 const char *Args[] = {""}; 471 472 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 473 ASSERT_TRUE(Invocation.getLangOpts()->CommentOpts.BlockCommandNames.empty()); 474 475 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 476 477 ASSERT_THAT(GeneratedArgs, 478 Not(Contains(HasSubstr("-fcomment-block-commands")))); 479 } 480 481 TEST_F(CommandLineTest, StringVectorCommaJoinedSingle) { 482 const char *Args[] = {"-fcomment-block-commands=x,y"}; 483 484 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 485 ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames, 486 std::vector<std::string>({"x", "y"})); 487 488 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 489 490 ASSERT_THAT(GeneratedArgs, 491 ContainsN(StrEq("-fcomment-block-commands=x,y"), 1)); 492 } 493 494 TEST_F(CommandLineTest, StringVectorCommaJoinedMultiple) { 495 const char *Args[] = {"-fcomment-block-commands=x,y", 496 "-fcomment-block-commands=a,b"}; 497 498 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 499 ASSERT_EQ(Invocation.getLangOpts()->CommentOpts.BlockCommandNames, 500 std::vector<std::string>({"x", "y", "a", "b"})); 501 502 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 503 504 ASSERT_THAT(GeneratedArgs, 505 ContainsN(StrEq("-fcomment-block-commands=x,y,a,b"), 1)); 506 } 507 508 // A flag that should be parsed only if a condition is met. 509 510 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagNotPresent) { 511 const char *Args[] = {""}; 512 513 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 514 515 ASSERT_FALSE(Diags->hasErrorOccurred()); 516 ASSERT_FALSE(Invocation.getLangOpts()->SYCL); 517 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None); 518 519 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 520 521 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl")))); 522 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std=")))); 523 } 524 525 TEST_F(CommandLineTest, ConditionalParsingIfFalseFlagPresent) { 526 const char *Args[] = {"-sycl-std=2017"}; 527 528 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 529 530 ASSERT_FALSE(Diags->hasErrorOccurred()); 531 ASSERT_FALSE(Invocation.getLangOpts()->SYCL); 532 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None); 533 534 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 535 536 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fsycl")))); 537 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std=")))); 538 } 539 540 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagNotPresent) { 541 const char *Args[] = {"-fsycl"}; 542 543 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 544 545 ASSERT_FALSE(Diags->hasErrorOccurred()); 546 ASSERT_TRUE(Invocation.getLangOpts()->SYCL); 547 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_None); 548 549 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 550 551 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl"))); 552 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-sycl-std=")))); 553 } 554 555 TEST_F(CommandLineTest, ConditionalParsingIfTrueFlagPresent) { 556 const char *Args[] = {"-fsycl", "-sycl-std=2017"}; 557 558 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 559 560 ASSERT_FALSE(Diags->hasErrorOccurred()); 561 ASSERT_TRUE(Invocation.getLangOpts()->SYCL); 562 ASSERT_EQ(Invocation.getLangOpts()->getSYCLVersion(), LangOptions::SYCL_2017); 563 564 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 565 566 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fsycl"))); 567 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-sycl-std=2017"))); 568 } 569 570 // Wide integer option. 571 572 TEST_F(CommandLineTest, WideIntegerHighValue) { 573 const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"}; 574 575 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 576 577 ASSERT_FALSE(Diags->hasErrorOccurred()); 578 ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp, 579 1609827494445723662ull); 580 } 581 582 // Tree of boolean options that can be (directly or transitively) implied by 583 // their parent: 584 // 585 // * -cl-unsafe-math-optimizations 586 // * -cl-mad-enable 587 // * -menable-unsafe-fp-math 588 // * -freciprocal-math 589 590 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) { 591 const char *Args[] = {""}; 592 593 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 594 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); 595 ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 596 ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath); 597 ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip); 598 599 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 600 601 // Not generated - missing. 602 ASSERT_THAT(GeneratedArgs, 603 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 604 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 605 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 606 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 607 } 608 609 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) { 610 const char *Args[] = {"-cl-unsafe-math-optimizations"}; 611 612 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 613 // Explicitly provided root flag. 614 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); 615 // Directly implied by explicitly provided root flag. 616 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 617 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 618 // Transitively implied by explicitly provided root flag. 619 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 620 621 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 622 623 // Generated - explicitly provided. 624 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 625 // Not generated - implied by the generated root flag. 626 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 627 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 628 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 629 } 630 631 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) { 632 const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable", 633 "-menable-unsafe-fp-math", "-freciprocal-math"}; 634 635 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 636 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); 637 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 638 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 639 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 640 641 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 642 643 // Generated - explicitly provided. 644 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 645 // Not generated - implied by their generated parent. 646 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 647 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 648 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 649 } 650 651 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) { 652 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math", 653 "-freciprocal-math"}; 654 655 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 656 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); 657 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 658 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 659 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 660 661 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 662 // Not generated - missing. 663 ASSERT_THAT(GeneratedArgs, 664 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 665 // Generated - explicitly provided. 666 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 667 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 668 // Not generated - implied by its generated parent. 669 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 670 } 671 672 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) { 673 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"}; 674 675 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 676 677 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 678 679 // Present options that were not implied are generated. 680 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 681 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 682 } 683 684 // Diagnostic option. 685 686 TEST_F(CommandLineTest, DiagnosticOptionPresent) { 687 const char *Args[] = {"-verify=xyz"}; 688 689 ASSERT_TRUE(CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags)); 690 691 ASSERT_EQ(Invocation.getDiagnosticOpts().VerifyPrefixes, 692 std::vector<std::string>({"xyz"})); 693 694 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 695 696 ASSERT_THAT(GeneratedArgs, ContainsN(StrEq("-verify=xyz"), 1)); 697 } 698 } // anonymous namespace 699