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