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 struct OptsPopulationTest : public ::testing::Test { 26 IntrusiveRefCntPtr<DiagnosticsEngine> Diags; 27 CompilerInvocation CInvok; 28 29 OptsPopulationTest() 30 : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions())) {} 31 }; 32 33 class CC1CommandLineGenerationTest : public ::testing::Test { 34 public: 35 IntrusiveRefCntPtr<DiagnosticsEngine> Diags; 36 SmallVector<const char *, 32> GeneratedArgs; 37 SmallVector<std::string, 32> GeneratedArgsStorage; 38 39 const char *operator()(const Twine &Arg) { 40 return GeneratedArgsStorage.emplace_back(Arg.str()).c_str(); 41 } 42 43 CC1CommandLineGenerationTest() 44 : Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions())) {} 45 }; 46 47 TEST_F(OptsPopulationTest, OptIsInitializedWithCustomDefaultValue) { 48 const char *Args[] = {"clang", "-xc++"}; 49 50 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 51 52 ASSERT_TRUE(CInvok.getFrontendOpts().UseTemporary); 53 } 54 55 TEST_F(OptsPopulationTest, OptOfNegativeFlagIsPopulatedWithFalse) { 56 const char *Args[] = {"clang", "-xc++", "-fno-temp-file"}; 57 58 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 59 60 ASSERT_FALSE(CInvok.getFrontendOpts().UseTemporary); 61 } 62 63 TEST_F(OptsPopulationTest, OptsOfImpliedPositiveFlagArePopulatedWithTrue) { 64 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; 65 66 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 67 68 // Explicitly provided flag. 69 ASSERT_TRUE(CInvok.getLangOpts()->CLUnsafeMath); 70 71 // Flags directly implied by explicitly provided flag. 72 ASSERT_TRUE(CInvok.getCodeGenOpts().LessPreciseFPMAD); 73 ASSERT_TRUE(CInvok.getLangOpts()->UnsafeFPMath); 74 75 // Flag transitively implied by explicitly provided flag. 76 ASSERT_TRUE(CInvok.getLangOpts()->AllowRecip); 77 } 78 79 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineFlag) { 80 const char *Args[] = {"clang", "-xc++", "-fmodules-strict-context-hash", "-"}; 81 82 CompilerInvocation CInvok; 83 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 84 85 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 86 87 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fmodules-strict-context-hash"))); 88 } 89 90 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineSeparate) { 91 const char *TripleCStr = "i686-apple-darwin9"; 92 const char *Args[] = {"clang", "-xc++", "-triple", TripleCStr, "-"}; 93 94 CompilerInvocation CInvok; 95 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 96 97 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 98 99 ASSERT_THAT(GeneratedArgs, Contains(StrEq(TripleCStr))); 100 } 101 102 TEST_F(CC1CommandLineGenerationTest, 103 CanGenerateCC1CommandLineSeparateRequiredPresent) { 104 const std::string DefaultTriple = 105 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 106 const char *Args[] = {"clang", "-xc++", "-triple", DefaultTriple.c_str(), 107 "-"}; 108 109 CompilerInvocation CInvok; 110 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 111 112 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 113 114 // Triple should always be emitted even if it is the default 115 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 116 } 117 118 TEST_F(CC1CommandLineGenerationTest, 119 CanGenerateCC1CommandLineSeparateRequiredAbsent) { 120 const std::string DefaultTriple = 121 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 122 const char *Args[] = {"clang", "-xc++", "-"}; 123 124 CompilerInvocation CInvok; 125 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 126 127 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 128 129 // Triple should always be emitted even if it is the default 130 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 131 } 132 133 TEST_F(CC1CommandLineGenerationTest, CanGenerateCC1CommandLineSeparateEnum) { 134 const char *RelocationModelCStr = "static"; 135 const char *Args[] = {"clang", "-xc++", "-mrelocation-model", 136 RelocationModelCStr, "-"}; 137 138 CompilerInvocation CInvok; 139 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 140 141 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 142 143 // Non default relocation model 144 ASSERT_THAT(GeneratedArgs, Contains(StrEq(RelocationModelCStr))); 145 GeneratedArgs.clear(); 146 147 RelocationModelCStr = "pic"; 148 Args[3] = RelocationModelCStr; 149 150 CompilerInvocation CInvok1; 151 CompilerInvocation::CreateFromArgs(CInvok1, Args, *Diags); 152 153 CInvok1.generateCC1CommandLine(GeneratedArgs, *this); 154 ASSERT_THAT(GeneratedArgs, Each(StrNe(RelocationModelCStr))); 155 } 156 157 TEST_F(CC1CommandLineGenerationTest, NotPresentNegativeFlagNotGenerated) { 158 const char *Args[] = {"clang", "-xc++"}; 159 160 CompilerInvocation CInvok; 161 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 162 163 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 164 165 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file")))); 166 } 167 168 TEST_F(CC1CommandLineGenerationTest, PresentNegativeFlagGenerated) { 169 const char *Args[] = {"clang", "-xc++", "-fno-temp-file"}; 170 171 CompilerInvocation CInvok; 172 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 173 174 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 175 176 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); 177 } 178 179 TEST_F(CC1CommandLineGenerationTest, NotPresentAndNotImpliedNotGenerated) { 180 const char *Args[] = {"clang", "-xc++"}; 181 182 CompilerInvocation CInvok; 183 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 184 185 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 186 187 // Missing options are not generated. 188 ASSERT_THAT(GeneratedArgs, 189 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 190 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 191 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 192 } 193 194 TEST_F(CC1CommandLineGenerationTest, NotPresentAndImpliedNotGenerated) { 195 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; 196 197 CompilerInvocation CInvok; 198 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 199 200 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 201 202 // Missing options that were implied are not generated. 203 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 204 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 205 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 206 } 207 208 TEST_F(CC1CommandLineGenerationTest, PresentAndImpliedNotGenerated) { 209 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations", 210 "-cl-mad-enable", "-menable-unsafe-fp-math"}; 211 212 CompilerInvocation CInvok; 213 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 214 215 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 216 217 // Present options that were also implied are not generated. 218 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 219 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 220 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 221 } 222 223 TEST_F(CC1CommandLineGenerationTest, PresentAndNotImpliedGenerated) { 224 const char *Args[] = {"clang", "-xc++", "-cl-mad-enable", 225 "-menable-unsafe-fp-math"}; 226 227 CompilerInvocation CInvok; 228 CompilerInvocation::CreateFromArgs(CInvok, Args, *Diags); 229 230 CInvok.generateCC1CommandLine(GeneratedArgs, *this); 231 232 // Present options that were not implied are generated. 233 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 234 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 235 } 236 } // anonymous namespace 237