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 // Wide integer option. 512 513 TEST_F(CommandLineTest, WideIntegerHighValue) { 514 const char *Args[] = {"-fbuild-session-timestamp=1609827494445723662"}; 515 516 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 517 518 ASSERT_FALSE(Diags->hasErrorOccurred()); 519 ASSERT_EQ(Invocation.getHeaderSearchOpts().BuildSessionTimestamp, 520 1609827494445723662ull); 521 } 522 523 // Tree of boolean options that can be (directly or transitively) implied by 524 // their parent: 525 // 526 // * -cl-unsafe-math-optimizations 527 // * -cl-mad-enable 528 // * -menable-unsafe-fp-math 529 // * -freciprocal-math 530 531 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) { 532 const char *Args[] = {""}; 533 534 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 535 536 ASSERT_FALSE(Diags->hasErrorOccurred()); 537 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); 538 ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 539 ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath); 540 ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip); 541 542 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 543 544 // Not generated - missing. 545 ASSERT_THAT(GeneratedArgs, 546 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 547 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 548 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 549 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 550 } 551 552 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) { 553 const char *Args[] = {"-cl-unsafe-math-optimizations"}; 554 555 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 556 557 ASSERT_FALSE(Diags->hasErrorOccurred()); 558 // Explicitly provided root flag. 559 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); 560 // Directly implied by explicitly provided root flag. 561 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 562 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 563 // Transitively implied by explicitly provided root flag. 564 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 565 566 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 567 568 // Generated - explicitly provided. 569 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 570 // Not generated - implied by the generated root flag. 571 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 572 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 573 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 574 } 575 576 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) { 577 const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable", 578 "-menable-unsafe-fp-math", "-freciprocal-math"}; 579 580 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 581 582 ASSERT_FALSE(Diags->hasErrorOccurred()); 583 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); 584 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 585 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 586 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 587 588 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 589 590 // Generated - explicitly provided. 591 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 592 // Not generated - implied by their generated parent. 593 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 594 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 595 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 596 } 597 598 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) { 599 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math", 600 "-freciprocal-math"}; 601 602 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 603 ASSERT_FALSE(Diags->hasErrorOccurred()); 604 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); 605 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 606 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 607 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 608 609 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 610 // Not generated - missing. 611 ASSERT_THAT(GeneratedArgs, 612 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 613 // Generated - explicitly provided. 614 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 615 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 616 // Not generated - implied by its generated parent. 617 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 618 } 619 620 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) { 621 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"}; 622 623 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 624 625 ASSERT_FALSE(Diags->hasErrorOccurred()); 626 627 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 628 629 // Present options that were not implied are generated. 630 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 631 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 632 } 633 } // anonymous namespace 634