[AMDGPU] Add pseudo scalar trans instructions for GFX12 (#75204)
[llvm-project.git] / clang / unittests / Lex / PPCallbacksTest.cpp
blobe0a27b5111821b56d5ad971f60312437e8b33c2d
1 //===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks 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 //===--------------------------------------------------------------===//
9 #include "clang/Lex/Preprocessor.h"
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/Basic/Diagnostic.h"
13 #include "clang/Basic/DiagnosticOptions.h"
14 #include "clang/Basic/FileManager.h"
15 #include "clang/Basic/LangOptions.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Basic/TargetOptions.h"
19 #include "clang/Lex/HeaderSearch.h"
20 #include "clang/Lex/HeaderSearchOptions.h"
21 #include "clang/Lex/ModuleLoader.h"
22 #include "clang/Lex/PreprocessorOptions.h"
23 #include "clang/Parse/Parser.h"
24 #include "clang/Sema/Sema.h"
25 #include "llvm/ADT/SmallString.h"
26 #include "llvm/Support/Path.h"
27 #include "gtest/gtest.h"
29 using namespace clang;
31 namespace {
33 // Stub to collect data from InclusionDirective callbacks.
34 class InclusionDirectiveCallbacks : public PPCallbacks {
35 public:
36 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
37 StringRef FileName, bool IsAngled,
38 CharSourceRange FilenameRange,
39 OptionalFileEntryRef File, StringRef SearchPath,
40 StringRef RelativePath, const Module *Imported,
41 SrcMgr::CharacteristicKind FileType) override {
42 this->HashLoc = HashLoc;
43 this->IncludeTok = IncludeTok;
44 this->FileName = FileName.str();
45 this->IsAngled = IsAngled;
46 this->FilenameRange = FilenameRange;
47 this->File = File;
48 this->SearchPath = SearchPath.str();
49 this->RelativePath = RelativePath.str();
50 this->Imported = Imported;
51 this->FileType = FileType;
54 SourceLocation HashLoc;
55 Token IncludeTok;
56 SmallString<16> FileName;
57 bool IsAngled;
58 CharSourceRange FilenameRange;
59 OptionalFileEntryRef File;
60 SmallString<16> SearchPath;
61 SmallString<16> RelativePath;
62 const Module* Imported;
63 SrcMgr::CharacteristicKind FileType;
66 class CondDirectiveCallbacks : public PPCallbacks {
67 public:
68 struct Result {
69 SourceRange ConditionRange;
70 ConditionValueKind ConditionValue;
72 Result(SourceRange R, ConditionValueKind K)
73 : ConditionRange(R), ConditionValue(K) {}
76 std::vector<Result> Results;
78 void If(SourceLocation Loc, SourceRange ConditionRange,
79 ConditionValueKind ConditionValue) override {
80 Results.emplace_back(ConditionRange, ConditionValue);
83 void Elif(SourceLocation Loc, SourceRange ConditionRange,
84 ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
85 Results.emplace_back(ConditionRange, ConditionValue);
89 // Stub to collect data from PragmaOpenCLExtension callbacks.
90 class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
91 public:
92 typedef struct {
93 SmallString<16> Name;
94 unsigned State;
95 } CallbackParameters;
97 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
99 void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
100 const clang::IdentifierInfo *Name,
101 clang::SourceLocation StateLoc,
102 unsigned State) override {
103 this->NameLoc = NameLoc;
104 this->Name = Name->getName();
105 this->StateLoc = StateLoc;
106 this->State = State;
109 SourceLocation NameLoc;
110 SmallString<16> Name;
111 SourceLocation StateLoc;
112 unsigned State;
115 class PragmaMarkCallbacks : public PPCallbacks {
116 public:
117 struct Mark {
118 SourceLocation Location;
119 std::string Trivia;
122 std::vector<Mark> Marks;
124 void PragmaMark(SourceLocation Loc, StringRef Trivia) override {
125 Marks.emplace_back(Mark{Loc, Trivia.str()});
129 // PPCallbacks test fixture.
130 class PPCallbacksTest : public ::testing::Test {
131 protected:
132 PPCallbacksTest()
133 : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
134 FileMgr(FileSystemOptions(), InMemoryFileSystem),
135 DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
136 Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
137 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
138 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
139 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
142 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
143 FileManager FileMgr;
144 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
145 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
146 DiagnosticsEngine Diags;
147 SourceManager SourceMgr;
148 LangOptions LangOpts;
149 std::shared_ptr<TargetOptions> TargetOpts;
150 IntrusiveRefCntPtr<TargetInfo> Target;
152 // Register a header path as a known file and add its location
153 // to search path.
154 void AddFakeHeader(HeaderSearch &HeaderInfo, const char *HeaderPath,
155 bool IsSystemHeader) {
156 // Tell FileMgr about header.
157 InMemoryFileSystem->addFile(HeaderPath, 0,
158 llvm::MemoryBuffer::getMemBuffer("\n"));
160 // Add header's parent path to search path.
161 StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
162 auto DE = FileMgr.getOptionalDirectoryRef(SearchPath);
163 DirectoryLookup DL(*DE, SrcMgr::C_User, false);
164 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
167 // Get the raw source string of the range.
168 StringRef GetSourceString(CharSourceRange Range) {
169 const char* B = SourceMgr.getCharacterData(Range.getBegin());
170 const char* E = SourceMgr.getCharacterData(Range.getEnd());
172 return StringRef(B, E - B);
175 StringRef GetSourceStringToEnd(CharSourceRange Range) {
176 const char *B = SourceMgr.getCharacterData(Range.getBegin());
177 const char *E = SourceMgr.getCharacterData(Range.getEnd());
179 return StringRef(
181 E - B + Lexer::MeasureTokenLength(Range.getEnd(), SourceMgr, LangOpts));
184 // Run lexer over SourceText and collect FilenameRange from
185 // the InclusionDirective callback.
186 CharSourceRange InclusionDirectiveFilenameRange(const char *SourceText,
187 const char *HeaderPath,
188 bool SystemHeader) {
189 std::unique_ptr<llvm::MemoryBuffer> Buf =
190 llvm::MemoryBuffer::getMemBuffer(SourceText);
191 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
193 TrivialModuleLoader ModLoader;
195 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
196 Diags, LangOpts, Target.get());
197 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
199 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
200 SourceMgr, HeaderInfo, ModLoader,
201 /*IILookup =*/nullptr,
202 /*OwnsHeaderSearch =*/false);
203 return InclusionDirectiveCallback(PP)->FilenameRange;
206 SrcMgr::CharacteristicKind InclusionDirectiveCharacteristicKind(
207 const char *SourceText, const char *HeaderPath, bool SystemHeader) {
208 std::unique_ptr<llvm::MemoryBuffer> Buf =
209 llvm::MemoryBuffer::getMemBuffer(SourceText);
210 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
212 TrivialModuleLoader ModLoader;
214 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
215 Diags, LangOpts, Target.get());
216 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
218 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
219 SourceMgr, HeaderInfo, ModLoader,
220 /*IILookup =*/nullptr,
221 /*OwnsHeaderSearch =*/false);
222 return InclusionDirectiveCallback(PP)->FileType;
225 InclusionDirectiveCallbacks *InclusionDirectiveCallback(Preprocessor &PP) {
226 PP.Initialize(*Target);
227 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
228 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
230 // Lex source text.
231 PP.EnterMainSourceFile();
232 PP.LexTokensUntilEOF();
234 // Callbacks have been executed at this point -- return filename range.
235 return Callbacks;
238 std::vector<CondDirectiveCallbacks::Result>
239 DirectiveExprRange(StringRef SourceText) {
240 TrivialModuleLoader ModLoader;
241 std::unique_ptr<llvm::MemoryBuffer> Buf =
242 llvm::MemoryBuffer::getMemBuffer(SourceText);
243 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
244 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
245 Diags, LangOpts, Target.get());
246 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
247 SourceMgr, HeaderInfo, ModLoader,
248 /*IILookup =*/nullptr,
249 /*OwnsHeaderSearch =*/false);
250 PP.Initialize(*Target);
251 auto *Callbacks = new CondDirectiveCallbacks;
252 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
254 // Lex source text.
255 PP.EnterMainSourceFile();
256 PP.LexTokensUntilEOF();
258 return Callbacks->Results;
261 std::vector<PragmaMarkCallbacks::Mark>
262 PragmaMarkCall(const char *SourceText) {
263 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
264 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.c");
265 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
267 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
268 Diags, LangOpts, Target.get());
269 TrivialModuleLoader ModLoader;
271 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
272 SourceMgr, HeaderInfo, ModLoader, /*IILookup=*/nullptr,
273 /*OwnsHeaderSearch=*/false);
274 PP.Initialize(*Target);
276 auto *Callbacks = new PragmaMarkCallbacks;
277 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
279 // Lex source text.
280 PP.EnterMainSourceFile();
281 PP.LexTokensUntilEOF();
283 return Callbacks->Marks;
286 PragmaOpenCLExtensionCallbacks::CallbackParameters
287 PragmaOpenCLExtensionCall(const char *SourceText) {
288 LangOptions OpenCLLangOpts;
289 OpenCLLangOpts.OpenCL = 1;
291 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
292 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
293 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
295 TrivialModuleLoader ModLoader;
296 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
297 Diags, OpenCLLangOpts, Target.get());
299 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
300 OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
301 /*IILookup =*/nullptr,
302 /*OwnsHeaderSearch =*/false);
303 PP.Initialize(*Target);
305 // parser actually sets correct pragma handlers for preprocessor
306 // according to LangOptions, so we init Parser to register opencl
307 // pragma handlers
308 ASTContext Context(OpenCLLangOpts, SourceMgr, PP.getIdentifierTable(),
309 PP.getSelectorTable(), PP.getBuiltinInfo(), PP.TUKind);
310 Context.InitBuiltinTypes(*Target);
312 ASTConsumer Consumer;
313 Sema S(PP, Context, Consumer);
314 Parser P(PP, S, false);
315 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
316 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
318 // Lex source text.
319 PP.EnterMainSourceFile();
320 PP.LexTokensUntilEOF();
322 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
323 Callbacks->Name,
324 Callbacks->State
326 return RetVal;
330 TEST_F(PPCallbacksTest, UserFileCharacteristics) {
331 const char *Source = "#include \"quoted.h\"\n";
333 SrcMgr::CharacteristicKind Kind =
334 InclusionDirectiveCharacteristicKind(Source, "/quoted.h", false);
336 ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
339 TEST_F(PPCallbacksTest, QuotedFilename) {
340 const char* Source =
341 "#include \"quoted.h\"\n";
343 CharSourceRange Range =
344 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
346 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
349 TEST_F(PPCallbacksTest, AngledFilename) {
350 const char* Source =
351 "#include <angled.h>\n";
353 CharSourceRange Range =
354 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
356 ASSERT_EQ("<angled.h>", GetSourceString(Range));
359 TEST_F(PPCallbacksTest, QuotedInMacro) {
360 const char* Source =
361 "#define MACRO_QUOTED \"quoted.h\"\n"
362 "#include MACRO_QUOTED\n";
364 CharSourceRange Range =
365 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
367 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
370 TEST_F(PPCallbacksTest, AngledInMacro) {
371 const char* Source =
372 "#define MACRO_ANGLED <angled.h>\n"
373 "#include MACRO_ANGLED\n";
375 CharSourceRange Range =
376 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
378 ASSERT_EQ("<angled.h>", GetSourceString(Range));
381 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
382 const char* Source =
383 "#define MACRO_STRINGIZED(x) #x\n"
384 "#include MACRO_STRINGIZED(quoted.h)\n";
386 CharSourceRange Range =
387 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
389 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
392 TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
393 const char* Source =
394 "#define MACRO_ANGLED <angled.h>\n"
395 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
396 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
398 CharSourceRange Range =
399 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
401 ASSERT_EQ("<angled.h>", GetSourceString(Range));
404 TEST_F(PPCallbacksTest, TrigraphFilename) {
405 const char* Source =
406 "#include \"tri\?\?-graph.h\"\n";
408 CharSourceRange Range =
409 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
411 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
414 TEST_F(PPCallbacksTest, TrigraphInMacro) {
415 const char* Source =
416 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
417 "#include MACRO_TRIGRAPH\n";
419 CharSourceRange Range =
420 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
422 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
425 TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
426 const char *SourceText = "#include \"skipped.h\"\n";
428 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
429 llvm::MemoryBuffer::getMemBuffer(SourceText);
430 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
432 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
433 Diags, LangOpts, Target.get());
434 TrivialModuleLoader ModLoader;
436 DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;
437 DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts.get(), DiagConsumer);
438 Preprocessor PP(std::make_shared<PreprocessorOptions>(), FileNotFoundDiags,
439 LangOpts, SourceMgr, HeaderInfo, ModLoader,
440 /*IILookup=*/nullptr,
441 /*OwnsHeaderSearch=*/false);
442 PP.Initialize(*Target);
444 class FileNotFoundCallbacks : public PPCallbacks {
445 public:
446 unsigned int NumCalls = 0;
447 bool FileNotFound(StringRef FileName) override {
448 NumCalls++;
449 return FileName == "skipped.h";
453 auto *Callbacks = new FileNotFoundCallbacks;
454 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
456 // Lex source text.
457 PP.EnterMainSourceFile();
458 PP.LexTokensUntilEOF();
460 ASSERT_EQ(1u, Callbacks->NumCalls);
461 ASSERT_EQ(0u, DiagConsumer->getNumErrors());
464 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
465 const char* Source =
466 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
468 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
469 PragmaOpenCLExtensionCall(Source);
471 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
472 unsigned ExpectedState = 1;
473 ASSERT_EQ(ExpectedState, Parameters.State);
476 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
477 const char* Source =
478 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
480 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
481 PragmaOpenCLExtensionCall(Source);
483 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
484 unsigned ExpectedState = 0;
485 ASSERT_EQ(ExpectedState, Parameters.State);
488 TEST_F(PPCallbacksTest, CollectMarks) {
489 const char *Source =
490 "#pragma mark\n"
491 "#pragma mark\r\n"
492 "#pragma mark - trivia\n"
493 "#pragma mark - trivia\r\n";
495 auto Marks = PragmaMarkCall(Source);
497 ASSERT_EQ(4u, Marks.size());
498 ASSERT_TRUE(Marks[0].Trivia.empty());
499 ASSERT_TRUE(Marks[1].Trivia.empty());
500 ASSERT_FALSE(Marks[2].Trivia.empty());
501 ASSERT_FALSE(Marks[3].Trivia.empty());
502 ASSERT_EQ(" - trivia", Marks[2].Trivia);
503 ASSERT_EQ(" - trivia", Marks[3].Trivia);
506 TEST_F(PPCallbacksTest, DirectiveExprRanges) {
507 const auto &Results1 = DirectiveExprRange("#if FLUZZY_FLOOF\n#endif\n");
508 EXPECT_EQ(Results1.size(), 1U);
509 EXPECT_EQ(
510 GetSourceStringToEnd(CharSourceRange(Results1[0].ConditionRange, false)),
511 "FLUZZY_FLOOF");
513 const auto &Results2 = DirectiveExprRange("#if 1 + 4 < 7\n#endif\n");
514 EXPECT_EQ(Results2.size(), 1U);
515 EXPECT_EQ(
516 GetSourceStringToEnd(CharSourceRange(Results2[0].ConditionRange, false)),
517 "1 + 4 < 7");
519 const auto &Results3 = DirectiveExprRange("#if 1 + \\\n 2\n#endif\n");
520 EXPECT_EQ(Results3.size(), 1U);
521 EXPECT_EQ(
522 GetSourceStringToEnd(CharSourceRange(Results3[0].ConditionRange, false)),
523 "1 + \\\n 2");
525 const auto &Results4 = DirectiveExprRange("#if 0\n#elif FLOOFY\n#endif\n");
526 EXPECT_EQ(Results4.size(), 2U);
527 EXPECT_EQ(
528 GetSourceStringToEnd(CharSourceRange(Results4[0].ConditionRange, false)),
529 "0");
530 EXPECT_EQ(
531 GetSourceStringToEnd(CharSourceRange(Results4[1].ConditionRange, false)),
532 "FLOOFY");
534 const auto &Results5 = DirectiveExprRange("#if 1\n#elif FLOOFY\n#endif\n");
535 EXPECT_EQ(Results5.size(), 2U);
536 EXPECT_EQ(
537 GetSourceStringToEnd(CharSourceRange(Results5[0].ConditionRange, false)),
538 "1");
539 EXPECT_EQ(
540 GetSourceStringToEnd(CharSourceRange(Results5[1].ConditionRange, false)),
541 "FLOOFY");
543 const auto &Results6 =
544 DirectiveExprRange("#if defined(FLUZZY_FLOOF)\n#endif\n");
545 EXPECT_EQ(Results6.size(), 1U);
546 EXPECT_EQ(
547 GetSourceStringToEnd(CharSourceRange(Results6[0].ConditionRange, false)),
548 "defined(FLUZZY_FLOOF)");
550 const auto &Results7 =
551 DirectiveExprRange("#if 1\n#elif defined(FLOOFY)\n#endif\n");
552 EXPECT_EQ(Results7.size(), 2U);
553 EXPECT_EQ(
554 GetSourceStringToEnd(CharSourceRange(Results7[0].ConditionRange, false)),
555 "1");
556 EXPECT_EQ(
557 GetSourceStringToEnd(CharSourceRange(Results7[1].ConditionRange, false)),
558 "defined(FLOOFY)");
560 const auto &Results8 =
561 DirectiveExprRange("#define FLOOFY 0\n#if __FILE__ > FLOOFY\n#endif\n");
562 EXPECT_EQ(Results8.size(), 1U);
563 EXPECT_EQ(
564 GetSourceStringToEnd(CharSourceRange(Results8[0].ConditionRange, false)),
565 "__FILE__ > FLOOFY");
566 EXPECT_EQ(
567 Lexer::getSourceText(CharSourceRange(Results8[0].ConditionRange, false),
568 SourceMgr, LangOpts),
569 "__FILE__ > FLOOFY");
572 } // namespace