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 "llvm/Support/Host.h" 12 13 #include "gmock/gmock.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 using namespace clang; 18 19 using ::testing::Contains; 20 using ::testing::Each; 21 using ::testing::StrEq; 22 using ::testing::StrNe; 23 24 namespace { 25 26 class CC1CommandLineGenerationTest : public ::testing::Test { 27 public: 28 IntrusiveRefCntPtr<DiagnosticsEngine> Diags; 29 SmallVector<const char *, 32> GeneratedArgs; 30 SmallVector<std::string, 32> GeneratedArgsStorage; 31 32 const char *operator()(const Twine &Arg) { 33 return GeneratedArgsStorage.emplace_back(Arg.str()).c_str(); 34 } 35 36 CC1CommandLineGenerationTest() 37 : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions())) {} 38 }; 39 40 TEST(OptsPopulationTest, CanPopulateOptsWithImpliedFlags) { 41 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; 42 43 auto Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions()); 44 45 CompilerInvocation CInvok; 46 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 47 48 // Explicitly provided flag. 49 ASSERT_EQ(CInvok.getLangOpts()->CLUnsafeMath, true); 50 51 // Flags directly implied by explicitly provided flag. 52 ASSERT_EQ(CInvok.getCodeGenOpts().LessPreciseFPMAD, true); 53 ASSERT_EQ(CInvok.getLangOpts()->UnsafeFPMath, true); 54 55 // Flag transitively implied by explicitly provided flag. 56 ASSERT_EQ(CInvok.getLangOpts()->AllowRecip, true); 57 } 58 59 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineFlag) { 60 const char *Args[] = {"clang", "-xc++", "-fmodules-strict-context-hash", "-"}; 61 62 CompilerInvocation CInvok; 63 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 64 65 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 66 67 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash"))); 68 } 69 70 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineSeparate) { 71 const char *TripleCStr = "i686-apple-darwin9"; 72 const char *Args[] = {"clang", "-xc++", "-triple", TripleCStr, "-"}; 73 74 CompilerInvocation CInvok; 75 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 76 77 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 78 79 ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr))); 80 } 81 82 TEST_F(CC1CommandLineGenerationTest, 83 CanGenerateCC1CommandLineSeparateRequiredPresent) { 84 const std::string DefaultTriple = 85 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 86 const char *Args[] = {"clang", "-xc++", "-triple", DefaultTriple.c_str(), 87 "-"}; 88 89 CompilerInvocation CInvok; 90 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 91 92 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 93 94 // Triple should always be emitted even if it is the default 95 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 96 } 97 98 TEST_F(CC1CommandLineGenerationTest, 99 CanGenerateCC1CommandLineSeparateRequiredAbsent) { 100 const std::string DefaultTriple = 101 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 102 const char *Args[] = {"clang", "-xc++", "-"}; 103 104 CompilerInvocation CInvok; 105 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 106 107 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 108 109 // Triple should always be emitted even if it is the default 110 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 111 } 112 113 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineSeparateEnum) { 114 const char *RelocationModelCStr = "static"; 115 const char *Args[] = {"clang", "-xc++", "-mrelocation-model", 116 RelocationModelCStr, "-"}; 117 118 CompilerInvocation CInvok; 119 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 120 121 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 122 123 // Non default relocation model 124 ASSERT_THAT(GeneratedArgs, Contains(StrEq(RelocationModelCStr))); 125 GeneratedArgs.clear(); 126 127 RelocationModelCStr = "pic"; 128 Args[3] = RelocationModelCStr; 129 130 CompilerInvocation CInvok1; 131 CompilerInvocation::CreateFromArgs(CInvok1, Args, *Diags); 132 133 CInvok1.generateCC1CommandLine(GeneratedArgs, *this); 134 ASSERT_THAT(GeneratedArgs, Each(StrNe(RelocationModelCStr))); 135 } 136 137 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineImpliedFlags) { 138 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations", 139 "-cl-mad-enable", "-menable-unsafe-fp-math"}; 140 141 CompilerInvocation CInvok; 142 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 143 144 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 145 146 // Explicitly provided flags that were also implied by another flag are not 147 // generated. 148 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 149 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 150 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 151 } 152 153 } // anonymous namespace 154