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