xref: /llvm-project/clang/unittests/Frontend/CompilerInvocationTest.cpp (revision 2b84efa00040410d97aff403788ee5d96b1046e2)
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