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