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