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 // Boolean option with a keypath that defaults to true. 43 // The only flag with a negative spelling can set the keypath to false. 44 45 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagNotPresent) { 46 const char *Args[] = {""}; 47 48 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 49 50 ASSERT_FALSE(Diags->hasErrorOccurred()); 51 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary); 52 53 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 54 55 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file")))); 56 } 57 58 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagPresent) { 59 const char *Args[] = {"-fno-temp-file"}; 60 61 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 62 63 ASSERT_FALSE(Diags->hasErrorOccurred()); 64 ASSERT_FALSE(Invocation.getFrontendOpts().UseTemporary); 65 66 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 67 68 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); 69 } 70 71 TEST_F(CommandLineTest, BoolOptionDefaultTrueSingleFlagUnknownPresent) { 72 const char *Args[] = {"-ftemp-file"}; 73 74 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 75 76 // Driver-only flag. 77 ASSERT_TRUE(Diags->hasErrorOccurred()); 78 ASSERT_TRUE(Invocation.getFrontendOpts().UseTemporary); 79 } 80 81 // Boolean option with a keypath that defaults to true. 82 // The flag with negative spelling can set the keypath to false. 83 // The flag with positive spelling can reset the keypath to true. 84 85 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNone) { 86 const char *Args[] = {""}; 87 88 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 89 ASSERT_FALSE(Diags->hasErrorOccurred()); 90 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); 91 92 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 93 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink")))); 94 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-autolink")))); 95 } 96 97 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentNegChange) { 98 const char *Args[] = {"-fno-autolink"}; 99 100 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 101 ASSERT_FALSE(Diags->hasErrorOccurred()); 102 ASSERT_FALSE(Invocation.getCodeGenOpts().Autolink); 103 104 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 105 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-autolink"))); 106 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fautolink")))); 107 } 108 109 TEST_F(CommandLineTest, BoolOptionDefaultTruePresentPosReset) { 110 const char *Args[] = {"-fautolink"}; 111 112 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 113 ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. 114 ASSERT_TRUE(Invocation.getCodeGenOpts().Autolink); 115 } 116 117 // Boolean option with a keypath that defaults to false. 118 // The flag with negative spelling can set the keypath to true. 119 // The flag with positive spelling can reset the keypath to false. 120 121 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNone) { 122 const char *Args[] = {""}; 123 124 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 125 ASSERT_FALSE(Diags->hasErrorOccurred()); 126 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables); 127 128 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 129 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables")))); 130 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-inline-line-tables")))); 131 } 132 133 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegChange) { 134 const char *Args[] = {"-gno-inline-line-tables"}; 135 136 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 137 ASSERT_FALSE(Diags->hasErrorOccurred()); 138 ASSERT_TRUE(Invocation.getCodeGenOpts().NoInlineLineTables); 139 140 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 141 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gno-inline-line-tables"))); 142 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-ginline-line-tables")))); 143 } 144 145 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosReset) { 146 const char *Args[] = {"-ginline-line-tables"}; 147 148 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 149 ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. 150 ASSERT_FALSE(Invocation.getCodeGenOpts().NoInlineLineTables); 151 } 152 153 // Boolean option with a keypath that defaults to false. 154 // The flag with positive spelling can set the keypath to true. 155 // The flag with negative spelling can reset the keypath to false. 156 157 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNoneX) { 158 const char *Args[] = {""}; 159 160 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 161 ASSERT_FALSE(Diags->hasErrorOccurred()); 162 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash); 163 164 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 165 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gcodeview-ghash")))); 166 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash")))); 167 } 168 169 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentPosChange) { 170 const char *Args[] = {"-gcodeview-ghash"}; 171 172 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 173 ASSERT_FALSE(Diags->hasErrorOccurred()); 174 ASSERT_TRUE(Invocation.getCodeGenOpts().CodeViewGHash); 175 176 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 177 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-gcodeview-ghash"))); 178 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-gno-codeview-ghash")))); 179 } 180 181 TEST_F(CommandLineTest, BoolOptionDefaultFalsePresentNegReset) { 182 const char *Args[] = {"-gno-codeview-ghash"}; 183 184 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 185 ASSERT_TRUE(Diags->hasErrorOccurred()); // Driver-only flag. 186 ASSERT_FALSE(Invocation.getCodeGenOpts().CodeViewGHash); 187 } 188 189 // Boolean option with a keypath that defaults to an arbitrary expression. 190 // The flag with positive spelling can set the keypath to true. 191 // The flag with negative spelling can set the keypath to false. 192 193 static constexpr unsigned PassManagerDefault = 194 !static_cast<unsigned>(LLVM_ENABLE_NEW_PASS_MANAGER); 195 196 static constexpr const char *PassManagerResetByFlag = 197 LLVM_ENABLE_NEW_PASS_MANAGER ? "-fno-legacy-pass-manager" 198 : "-flegacy-pass-manager"; 199 200 static constexpr const char *PassManagerChangedByFlag = 201 LLVM_ENABLE_NEW_PASS_MANAGER ? "-flegacy-pass-manager" 202 : "-fno-legacy-pass-manager"; 203 204 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentNone) { 205 const char *Args = {""}; 206 207 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 208 209 ASSERT_FALSE(Diags->hasErrorOccurred()); 210 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault); 211 212 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 213 214 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag)))); 215 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag)))); 216 } 217 218 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentChange) { 219 const char *Args[] = {PassManagerChangedByFlag}; 220 221 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 222 ASSERT_FALSE(Diags->hasErrorOccurred()); 223 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, !PassManagerDefault); 224 225 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 226 ASSERT_THAT(GeneratedArgs, Contains(StrEq(PassManagerChangedByFlag))); 227 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag)))); 228 } 229 230 TEST_F(CommandLineTest, BoolOptionDefaultArbitraryTwoFlagsPresentReset) { 231 const char *Args[] = {PassManagerResetByFlag}; 232 233 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 234 ASSERT_FALSE(Diags->hasErrorOccurred()); 235 ASSERT_EQ(Invocation.getCodeGenOpts().LegacyPassManager, PassManagerDefault); 236 237 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 238 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerResetByFlag)))); 239 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq(PassManagerChangedByFlag)))); 240 } 241 242 // Boolean option that gets the CC1Option flag from a let statement (which 243 // is applied **after** the record is defined): 244 // 245 // let Flags = [CC1Option] in { 246 // defm option : BoolOption<...>; 247 // } 248 249 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNone) { 250 const char *Args[] = {""}; 251 252 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 253 254 ASSERT_FALSE(Diags->hasErrorOccurred()); 255 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager); 256 257 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 258 259 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager")))); 260 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager")))); 261 } 262 263 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentPos) { 264 const char *Args[] = {"-fdebug-pass-manager"}; 265 266 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 267 268 ASSERT_FALSE(Diags->hasErrorOccurred()); 269 ASSERT_TRUE(Invocation.getCodeGenOpts().DebugPassManager); 270 271 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 272 273 ASSERT_EQ(count(GeneratedArgs, StringRef("-fdebug-pass-manager")), 1); 274 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager")))); 275 } 276 277 TEST_F(CommandLineTest, BoolOptionCC1ViaLetPresentNeg) { 278 const char *Args[] = {"-fno-debug-pass-manager"}; 279 280 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 281 282 ASSERT_FALSE(Diags->hasErrorOccurred()); 283 ASSERT_FALSE(Invocation.getCodeGenOpts().DebugPassManager); 284 285 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 286 287 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-debug-pass-manager")))); 288 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fdebug-pass-manager")))); 289 } 290 291 TEST_F(CommandLineTest, CanGenerateCC1CommandLineFlag) { 292 const char *Args[] = {"-fmodules-strict-context-hash"}; 293 294 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 295 296 ASSERT_FALSE(Diags->hasErrorOccurred()); 297 298 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 299 300 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash"))); 301 } 302 303 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparate) { 304 const char *TripleCStr = "i686-apple-darwin9"; 305 const char *Args[] = {"-triple", TripleCStr}; 306 307 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 308 309 ASSERT_FALSE(Diags->hasErrorOccurred()); 310 311 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 312 313 ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr))); 314 } 315 316 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredPresent) { 317 const std::string DefaultTriple = 318 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 319 const char *Args[] = {"-triple", DefaultTriple.c_str()}; 320 321 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 322 323 ASSERT_FALSE(Diags->hasErrorOccurred()); 324 325 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 326 327 // Triple should always be emitted even if it is the default 328 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 329 } 330 331 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) { 332 const std::string DefaultTriple = 333 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 334 const char *Args[] = {""}; 335 336 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 337 338 ASSERT_FALSE(Diags->hasErrorOccurred()); 339 340 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 341 342 // Triple should always be emitted even if it is the default 343 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 344 } 345 346 TEST_F(CommandLineTest, SeparateEnumNonDefault) { 347 const char *Args[] = {"-mrelocation-model", "static"}; 348 349 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 350 351 ASSERT_FALSE(Diags->hasErrorOccurred()); 352 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::Static); 353 354 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 355 356 // Non default relocation model. 357 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-mrelocation-model"))); 358 ASSERT_THAT(GeneratedArgs, Contains(StrEq("static"))); 359 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=static")))); 360 } 361 362 TEST_F(CommandLineTest, SeparateEnumDefault) { 363 const char *Args[] = {"-mrelocation-model", "pic"}; 364 365 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 366 367 ASSERT_FALSE(Diags->hasErrorOccurred()); 368 ASSERT_EQ(Invocation.getCodeGenOpts().RelocationModel, Reloc::Model::PIC_); 369 370 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 371 372 // Default relocation model. 373 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model")))); 374 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic")))); 375 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-mrelocation-model=pic")))); 376 } 377 378 TEST_F(CommandLineTest, JoinedEnumNonDefault) { 379 const char *Args[] = {"-fobjc-dispatch-method=non-legacy"}; 380 381 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 382 383 ASSERT_FALSE(Diags->hasErrorOccurred()); 384 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(), 385 CodeGenOptions::NonLegacy); 386 387 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 388 389 ASSERT_THAT(GeneratedArgs, 390 Contains(StrEq("-fobjc-dispatch-method=non-legacy"))); 391 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method=")))); 392 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("non-legacy")))); 393 } 394 395 TEST_F(CommandLineTest, JoinedEnumDefault) { 396 const char *Args[] = {"-fobjc-dispatch-method=legacy"}; 397 398 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 399 400 ASSERT_FALSE(Diags->hasErrorOccurred()); 401 ASSERT_EQ(Invocation.getCodeGenOpts().getObjCDispatchMethod(), 402 CodeGenOptions::Legacy); 403 404 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 405 406 ASSERT_THAT(GeneratedArgs, 407 Not(Contains(StrEq("-fobjc-dispatch-method=legacy")))); 408 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fobjc-dispatch-method=")))); 409 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("legacy")))); 410 } 411 412 TEST_F(CommandLineTest, StringVectorEmpty) { 413 const char *Args[] = {""}; 414 415 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 416 417 ASSERT_FALSE(Diags->hasErrorOccurred()); 418 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles.empty()); 419 420 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 421 ASSERT_THAT(GeneratedArgs, Not(Contains(HasSubstr("-fmodule-map-file=")))); 422 } 423 424 TEST_F(CommandLineTest, StringVectorSingle) { 425 const char *Args[] = {"-fmodule-map-file=a"}; 426 427 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 428 429 ASSERT_FALSE(Diags->hasErrorOccurred()); 430 ASSERT_EQ(Invocation.getFrontendOpts().ModuleMapFiles, 431 std::vector<std::string>({"a"})); 432 433 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 434 ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1); 435 } 436 437 TEST_F(CommandLineTest, StringVectorMultiple) { 438 const char *Args[] = {"-fmodule-map-file=a", "-fmodule-map-file=b"}; 439 440 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 441 442 ASSERT_FALSE(Diags->hasErrorOccurred()); 443 ASSERT_TRUE(Invocation.getFrontendOpts().ModuleMapFiles == 444 std::vector<std::string>({"a", "b"})); 445 446 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 447 ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=a")), 1); 448 ASSERT_EQ(count(GeneratedArgs, StringRef("-fmodule-map-file=b")), 1); 449 } 450 451 // Tree of boolean options that can be (directly or transitively) implied by 452 // their parent: 453 // 454 // * -cl-unsafe-math-optimizations 455 // * -cl-mad-enable 456 // * -menable-unsafe-fp-math 457 // * -freciprocal-math 458 459 TEST_F(CommandLineTest, ImpliedBoolOptionsNoFlagPresent) { 460 const char *Args[] = {""}; 461 462 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 463 464 ASSERT_FALSE(Diags->hasErrorOccurred()); 465 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); 466 ASSERT_FALSE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 467 ASSERT_FALSE(Invocation.getLangOpts()->UnsafeFPMath); 468 ASSERT_FALSE(Invocation.getLangOpts()->AllowRecip); 469 470 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 471 472 // Not generated - missing. 473 ASSERT_THAT(GeneratedArgs, 474 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 475 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 476 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 477 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 478 } 479 480 TEST_F(CommandLineTest, ImpliedBoolOptionsRootFlagPresent) { 481 const char *Args[] = {"-cl-unsafe-math-optimizations"}; 482 483 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 484 485 ASSERT_FALSE(Diags->hasErrorOccurred()); 486 // Explicitly provided root flag. 487 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); 488 // Directly implied by explicitly provided root flag. 489 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 490 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 491 // Transitively implied by explicitly provided root flag. 492 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 493 494 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 495 496 // Generated - explicitly provided. 497 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 498 // Not generated - implied by the generated root flag. 499 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 500 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 501 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 502 } 503 504 TEST_F(CommandLineTest, ImpliedBoolOptionsAllFlagsPresent) { 505 const char *Args[] = {"-cl-unsafe-math-optimizations", "-cl-mad-enable", 506 "-menable-unsafe-fp-math", "-freciprocal-math"}; 507 508 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 509 510 ASSERT_FALSE(Diags->hasErrorOccurred()); 511 ASSERT_TRUE(Invocation.getLangOpts()->CLUnsafeMath); 512 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 513 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 514 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 515 516 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 517 518 // Generated - explicitly provided. 519 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 520 // Not generated - implied by their generated parent. 521 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 522 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 523 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 524 } 525 526 TEST_F(CommandLineTest, ImpliedBoolOptionsImpliedFlagsPresent) { 527 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math", 528 "-freciprocal-math"}; 529 530 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 531 ASSERT_FALSE(Diags->hasErrorOccurred()); 532 ASSERT_FALSE(Invocation.getLangOpts()->CLUnsafeMath); 533 ASSERT_TRUE(Invocation.getCodeGenOpts().LessPreciseFPMAD); 534 ASSERT_TRUE(Invocation.getLangOpts()->UnsafeFPMath); 535 ASSERT_TRUE(Invocation.getLangOpts()->AllowRecip); 536 537 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 538 // Not generated - missing. 539 ASSERT_THAT(GeneratedArgs, 540 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 541 // Generated - explicitly provided. 542 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 543 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 544 // Not generated - implied by its generated parent. 545 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-freciprocal-math")))); 546 } 547 548 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) { 549 const char *Args[] = {"-cl-mad-enable", "-menable-unsafe-fp-math"}; 550 551 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 552 553 ASSERT_FALSE(Diags->hasErrorOccurred()); 554 555 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 556 557 // Present options that were not implied are generated. 558 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 559 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 560 } 561 } // anonymous namespace 562