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