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[] = {"clang", "-xc++"}; 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[] = {"clang", "-xc++", "-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[] = {"clang", "-xc++", "-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[] = {"clang", "-xc++", "-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[] = {"clang", "-xc++", "-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[] = {"clang", "-xc++", "-triple", DefaultTriple.c_str(), 95 "-"}; 96 97 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 98 99 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 100 101 // Triple should always be emitted even if it is the default 102 ASSERT_THAT(GeneratedArgs, Contains(StrEq(DefaultTriple.c_str()))); 103 } 104 105 TEST_F(CommandLineTest, CanGenerateCC1CommandLineSeparateRequiredAbsent) { 106 const std::string DefaultTriple = 107 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 108 const char *Args[] = {"clang", "-xc++", "-"}; 109 110 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 111 112 Invocation.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(CommandLineTest, CanGenerateCC1CommandLineSeparateEnumNonDefault) { 119 const char *Args[] = {"clang", "-xc++", "-mrelocation-model", "static", "-"}; 120 121 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 122 123 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 124 125 // Non default relocation model. 126 ASSERT_THAT(GeneratedArgs, Contains(StrEq("static"))); 127 } 128 129 TEST_F(CommandLineTest, CanGenerateCC1COmmandLineSeparateEnumDefault) { 130 const char *Args[] = {"clang", "-xc++", "-mrelocation-model", "pic", "-"}; 131 132 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 133 134 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 135 136 // Default relocation model. 137 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("pic")))); 138 } 139 140 TEST_F(CommandLineTest, NotPresentNegativeFlagNotGenerated) { 141 const char *Args[] = {"clang", "-xc++"}; 142 143 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 144 145 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 146 147 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-fno-temp-file")))); 148 } 149 150 TEST_F(CommandLineTest, PresentNegativeFlagGenerated) { 151 const char *Args[] = {"clang", "-xc++", "-fno-temp-file"}; 152 153 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 154 155 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 156 157 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-fno-temp-file"))); 158 } 159 160 TEST_F(CommandLineTest, NotPresentAndNotImpliedNotGenerated) { 161 const char *Args[] = {"clang", "-xc++"}; 162 163 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 164 165 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 166 167 // Missing options are not generated. 168 ASSERT_THAT(GeneratedArgs, 169 Not(Contains(StrEq("-cl-unsafe-math-optimizations")))); 170 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 171 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 172 } 173 174 TEST_F(CommandLineTest, NotPresentAndImpliedNotGenerated) { 175 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations"}; 176 177 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 178 179 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 180 181 // Missing options that were implied are not generated. 182 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 183 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 184 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 185 } 186 187 TEST_F(CommandLineTest, PresentAndImpliedNotGenerated) { 188 const char *Args[] = {"clang", "-xc++", "-cl-unsafe-math-optimizations", 189 "-cl-mad-enable", "-menable-unsafe-fp-math"}; 190 191 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 192 193 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 194 195 // Present options that were also implied are not generated. 196 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-unsafe-math-optimizations"))); 197 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-cl-mad-enable")))); 198 ASSERT_THAT(GeneratedArgs, Not(Contains(StrEq("-menable-unsafe-fp-math")))); 199 } 200 201 TEST_F(CommandLineTest, PresentAndNotImpliedGenerated) { 202 const char *Args[] = {"clang", "-xc++", "-cl-mad-enable", 203 "-menable-unsafe-fp-math"}; 204 205 CompilerInvocation::CreateFromArgs(Invocation, Args, *Diags); 206 207 Invocation.generateCC1CommandLine(GeneratedArgs, *this); 208 209 // Present options that were not implied are generated. 210 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-cl-mad-enable"))); 211 ASSERT_THAT(GeneratedArgs, Contains(StrEq("-menable-unsafe-fp-math"))); 212 } 213 } // anonymous namespace 214