Bug Summary

File:src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/clang/include/clang/Basic/FileEntry.h
Warning:line 64, column 13
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ModuleManager.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/libclangSerialization/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/clang/include -I /usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/libclangSerialization/../include -I /usr/src/gnu/usr.bin/clang/libclangSerialization/obj -I /usr/src/gnu/usr.bin/clang/libclangSerialization/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/libclangSerialization/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/clang/lib/Serialization/ModuleManager.cpp

/usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/clang/lib/Serialization/ModuleManager.cpp

1//===- ModuleManager.cpp - Module Manager ---------------------------------===//
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// This file defines the ModuleManager class, which manages a set of loaded
10// modules for the ASTReader.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Serialization/ModuleManager.h"
15#include "clang/Basic/FileManager.h"
16#include "clang/Basic/LLVM.h"
17#include "clang/Lex/HeaderSearch.h"
18#include "clang/Lex/ModuleMap.h"
19#include "clang/Serialization/GlobalModuleIndex.h"
20#include "clang/Serialization/InMemoryModuleCache.h"
21#include "clang/Serialization/ModuleFile.h"
22#include "clang/Serialization/PCHContainerOperations.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/SetVector.h"
25#include "llvm/ADT/SmallPtrSet.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/ADT/StringRef.h"
28#include "llvm/ADT/iterator.h"
29#include "llvm/Support/Chrono.h"
30#include "llvm/Support/DOTGraphTraits.h"
31#include "llvm/Support/ErrorOr.h"
32#include "llvm/Support/GraphWriter.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/VirtualFileSystem.h"
35#include <algorithm>
36#include <cassert>
37#include <memory>
38#include <string>
39#include <system_error>
40
41using namespace clang;
42using namespace serialization;
43
44ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
45 auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
46 /*CacheFailure=*/false);
47 if (Entry)
48 return lookup(*Entry);
49
50 return nullptr;
51}
52
53ModuleFile *ModuleManager::lookupByModuleName(StringRef Name) const {
54 if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
55 if (const FileEntry *File = Mod->getASTFile())
56 return lookup(File);
57
58 return nullptr;
59}
60
61ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
62 auto Known = Modules.find(File);
63 if (Known == Modules.end())
64 return nullptr;
65
66 return Known->second;
67}
68
69std::unique_ptr<llvm::MemoryBuffer>
70ModuleManager::lookupBuffer(StringRef Name) {
71 auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
72 /*CacheFailure=*/false);
73 if (!Entry)
74 return nullptr;
75 return std::move(InMemoryBuffers[*Entry]);
76}
77
78static bool checkSignature(ASTFileSignature Signature,
79 ASTFileSignature ExpectedSignature,
80 std::string &ErrorStr) {
81 if (!ExpectedSignature || Signature == ExpectedSignature)
82 return false;
83
84 ErrorStr =
85 Signature ? "signature mismatch" : "could not read module signature";
86 return true;
87}
88
89static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
90 SourceLocation ImportLoc) {
91 if (ImportedBy) {
92 MF.ImportedBy.insert(ImportedBy);
93 ImportedBy->Imports.insert(&MF);
94 } else {
95 if (!MF.DirectlyImported)
96 MF.ImportLoc = ImportLoc;
97
98 MF.DirectlyImported = true;
99 }
100}
101
102ModuleManager::AddModuleResult
103ModuleManager::addModule(StringRef FileName, ModuleKind Type,
104 SourceLocation ImportLoc, ModuleFile *ImportedBy,
105 unsigned Generation,
106 off_t ExpectedSize, time_t ExpectedModTime,
107 ASTFileSignature ExpectedSignature,
108 ASTFileSignatureReader ReadSignature,
109 ModuleFile *&Module,
110 std::string &ErrorStr) {
111 Module = nullptr;
112
113 // Look for the file entry. This only fails if the expected size or
114 // modification time differ.
115 OptionalFileEntryRefDegradesToFileEntryPtr Entry;
1
Calling defaulted default constructor for 'OptionalFileEntryRefDegradesToFileEntryPtr'
11
Returning from default constructor for 'OptionalFileEntryRefDegradesToFileEntryPtr'
116 if (Type == MK_ExplicitModule || Type == MK_PrebuiltModule) {
12
Assuming 'Type' is not equal to MK_ExplicitModule
13
Assuming 'Type' is not equal to MK_PrebuiltModule
14
Taking false branch
117 // If we're not expecting to pull this file out of the module cache, it
118 // might have a different mtime due to being moved across filesystems in
119 // a distributed build. The size must still match, though. (As must the
120 // contents, but we can't check that.)
121 ExpectedModTime = 0;
122 }
123 // Note: ExpectedSize and ExpectedModTime will be 0 for MK_ImplicitModule
124 // when using an ASTFileSignature.
125 if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) {
15
Calling 'ModuleManager::lookupModuleFile'
19
Returning from 'ModuleManager::lookupModuleFile'
20
Taking false branch
126 ErrorStr = "module file out of date";
127 return OutOfDate;
128 }
129
130 if (!Entry && FileName != "-") {
21
Taking false branch
131 ErrorStr = "module file not found";
132 return Missing;
133 }
134
135 // The ModuleManager's use of FileEntry nodes as the keys for its map of
136 // loaded modules is less than ideal. Uniqueness for FileEntry nodes is
137 // maintained by FileManager, which in turn uses inode numbers on hosts
138 // that support that. When coupled with the module cache's proclivity for
139 // turning over and deleting stale PCMs, this means entries for different
140 // module files can wind up reusing the same underlying inode. When this
141 // happens, subsequent accesses to the Modules map will disagree on the
142 // ModuleFile associated with a given file. In general, it is not sufficient
143 // to resolve this conundrum with a type like FileEntryRef that stores the
144 // name of the FileEntry node on first access because of path canonicalization
145 // issues. However, the paths constructed for implicit module builds are
146 // fully under Clang's control. We *can*, therefore, rely on their structure
147 // being consistent across operating systems and across subsequent accesses
148 // to the Modules map.
149 auto implicitModuleNamesMatch = [](ModuleKind Kind, const ModuleFile *MF,
150 const FileEntry *Entry) -> bool {
151 if (Kind != MK_ImplicitModule)
152 return true;
153 return Entry->getName() == MF->FileName;
154 };
155
156 // Check whether we already loaded this module, before
157 if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
22
Assuming 'ModuleEntry' is null
23
Taking false branch
158 if (implicitModuleNamesMatch(Type, ModuleEntry, Entry)) {
159 // Check the stored signature.
160 if (checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
161 return OutOfDate;
162
163 Module = ModuleEntry;
164 updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
165 return AlreadyLoaded;
166 }
167 }
168
169 // Allocate a new module.
170 auto NewModule = std::make_unique<ModuleFile>(Type, Generation);
171 NewModule->Index = Chain.size();
172 NewModule->FileName = FileName.str();
173 NewModule->File = Entry;
174 NewModule->ImportLoc = ImportLoc;
175 NewModule->InputFilesValidationTimestamp = 0;
176
177 if (NewModule->Kind == MK_ImplicitModule) {
24
Assuming field 'Kind' is not equal to MK_ImplicitModule
25
Taking false branch
178 std::string TimestampFilename = NewModule->getTimestampFilename();
179 llvm::vfs::Status Status;
180 // A cached stat value would be fine as well.
181 if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
182 NewModule->InputFilesValidationTimestamp =
183 llvm::sys::toTimeT(Status.getLastModificationTime());
184 }
185
186 // Load the contents of the module
187 if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
26
Taking false branch
188 // The buffer was already provided for us.
189 NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer));
190 // Since the cached buffer is reused, it is safe to close the file
191 // descriptor that was opened while stat()ing the PCM in
192 // lookupModuleFile() above, it won't be needed any longer.
193 Entry->closeFile();
194 } else if (llvm::MemoryBuffer *Buffer =
27
Assuming 'Buffer' is null
28
Taking false branch
195 getModuleCache().lookupPCM(FileName)) {
196 NewModule->Buffer = Buffer;
197 // As above, the file descriptor is no longer needed.
198 Entry->closeFile();
199 } else if (getModuleCache().shouldBuildPCM(FileName)) {
29
Assuming the condition is true
30
Taking true branch
200 // Report that the module is out of date, since we tried (and failed) to
201 // import it earlier.
202 Entry->closeFile();
31
Calling 'FileEntryRef::closeFile'
203 return OutOfDate;
204 } else {
205 // Open the AST file.
206 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
207 if (FileName == "-") {
208 Buf = llvm::MemoryBuffer::getSTDIN();
209 } else {
210 // Get a buffer of the file and close the file descriptor when done.
211 // The file is volatile because in a parallel build we expect multiple
212 // compiler processes to use the same module file rebuilding it if needed.
213 //
214 // RequiresNullTerminator is false because module files don't need it, and
215 // this allows the file to still be mmapped.
216 Buf = FileMgr.getBufferForFile(NewModule->File,
217 /*IsVolatile=*/true,
218 /*RequiresNullTerminator=*/false);
219 }
220
221 if (!Buf) {
222 ErrorStr = Buf.getError().message();
223 return Missing;
224 }
225
226 NewModule->Buffer = &getModuleCache().addPCM(FileName, std::move(*Buf));
227 }
228
229 // Initialize the stream.
230 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
231
232 // Read the signature eagerly now so that we can check it. Avoid calling
233 // ReadSignature unless there's something to check though.
234 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
235 ExpectedSignature, ErrorStr))
236 return OutOfDate;
237
238 // We're keeping this module. Store it everywhere.
239 Module = Modules[Entry] = NewModule.get();
240
241 updateModuleImports(*NewModule, ImportedBy, ImportLoc);
242
243 if (!NewModule->isModule())
244 PCHChain.push_back(NewModule.get());
245 if (!ImportedBy)
246 Roots.push_back(NewModule.get());
247
248 Chain.push_back(std::move(NewModule));
249 return NewlyLoaded;
250}
251
252void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) {
253 auto Last = end();
254 if (First == Last)
255 return;
256
257 // Explicitly clear VisitOrder since we might not notice it is stale.
258 VisitOrder.clear();
259
260 // Collect the set of module file pointers that we'll be removing.
261 llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
262 (llvm::pointer_iterator<ModuleIterator>(First)),
263 (llvm::pointer_iterator<ModuleIterator>(Last)));
264
265 auto IsVictim = [&](ModuleFile *MF) {
266 return victimSet.count(MF);
267 };
268 // Remove any references to the now-destroyed modules.
269 for (auto I = begin(); I != First; ++I) {
270 I->Imports.remove_if(IsVictim);
271 I->ImportedBy.remove_if(IsVictim);
272 }
273 Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
274 Roots.end());
275
276 // Remove the modules from the PCH chain.
277 for (auto I = First; I != Last; ++I) {
278 if (!I->isModule()) {
279 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
280 break;
281 }
282 }
283
284 // Delete the modules and erase them from the various structures.
285 for (ModuleIterator victim = First; victim != Last; ++victim) {
286 Modules.erase(victim->File);
287
288 if (modMap) {
289 StringRef ModuleName = victim->ModuleName;
290 if (Module *mod = modMap->findModule(ModuleName)) {
291 mod->setASTFile(None);
292 }
293 }
294 }
295
296 // Delete the modules.
297 Chain.erase(Chain.begin() + (First - begin()), Chain.end());
298}
299
300void
301ModuleManager::addInMemoryBuffer(StringRef FileName,
302 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
303 const FileEntry *Entry =
304 FileMgr.getVirtualFile(FileName, Buffer->getBufferSize(), 0);
305 InMemoryBuffers[Entry] = std::move(Buffer);
306}
307
308ModuleManager::VisitState *ModuleManager::allocateVisitState() {
309 // Fast path: if we have a cached state, use it.
310 if (FirstVisitState) {
311 VisitState *Result = FirstVisitState;
312 FirstVisitState = FirstVisitState->NextState;
313 Result->NextState = nullptr;
314 return Result;
315 }
316
317 // Allocate and return a new state.
318 return new VisitState(size());
319}
320
321void ModuleManager::returnVisitState(VisitState *State) {
322 assert(State->NextState == nullptr && "Visited state is in list?")((void)0);
323 State->NextState = FirstVisitState;
324 FirstVisitState = State;
325}
326
327void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
328 GlobalIndex = Index;
329 if (!GlobalIndex) {
330 ModulesInCommonWithGlobalIndex.clear();
331 return;
332 }
333
334 // Notify the global module index about all of the modules we've already
335 // loaded.
336 for (ModuleFile &M : *this)
337 if (!GlobalIndex->loadedModuleFile(&M))
338 ModulesInCommonWithGlobalIndex.push_back(&M);
339}
340
341void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
342 if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
343 return;
344
345 ModulesInCommonWithGlobalIndex.push_back(MF);
346}
347
348ModuleManager::ModuleManager(FileManager &FileMgr,
349 InMemoryModuleCache &ModuleCache,
350 const PCHContainerReader &PCHContainerRdr,
351 const HeaderSearch &HeaderSearchInfo)
352 : FileMgr(FileMgr), ModuleCache(&ModuleCache),
353 PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}
354
355ModuleManager::~ModuleManager() { delete FirstVisitState; }
356
357void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
358 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
359 // If the visitation order vector is the wrong size, recompute the order.
360 if (VisitOrder.size() != Chain.size()) {
361 unsigned N = size();
362 VisitOrder.clear();
363 VisitOrder.reserve(N);
364
365 // Record the number of incoming edges for each module. When we
366 // encounter a module with no incoming edges, push it into the queue
367 // to seed the queue.
368 SmallVector<ModuleFile *, 4> Queue;
369 Queue.reserve(N);
370 llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
371 UnusedIncomingEdges.resize(size());
372 for (ModuleFile &M : llvm::reverse(*this)) {
373 unsigned Size = M.ImportedBy.size();
374 UnusedIncomingEdges[M.Index] = Size;
375 if (!Size)
376 Queue.push_back(&M);
377 }
378
379 // Traverse the graph, making sure to visit a module before visiting any
380 // of its dependencies.
381 while (!Queue.empty()) {
382 ModuleFile *CurrentModule = Queue.pop_back_val();
383 VisitOrder.push_back(CurrentModule);
384
385 // For any module that this module depends on, push it on the
386 // stack (if it hasn't already been marked as visited).
387 for (auto M = CurrentModule->Imports.rbegin(),
388 MEnd = CurrentModule->Imports.rend();
389 M != MEnd; ++M) {
390 // Remove our current module as an impediment to visiting the
391 // module we depend on. If we were the last unvisited module
392 // that depends on this particular module, push it into the
393 // queue to be visited.
394 unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
395 if (NumUnusedEdges && (--NumUnusedEdges == 0))
396 Queue.push_back(*M);
397 }
398 }
399
400 assert(VisitOrder.size() == N && "Visitation order is wrong?")((void)0);
401
402 delete FirstVisitState;
403 FirstVisitState = nullptr;
404 }
405
406 VisitState *State = allocateVisitState();
407 unsigned VisitNumber = State->NextVisitNumber++;
408
409 // If the caller has provided us with a hit-set that came from the global
410 // module index, mark every module file in common with the global module
411 // index that is *not* in that set as 'visited'.
412 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
413 for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
414 {
415 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
416 if (!ModuleFilesHit->count(M))
417 State->VisitNumber[M->Index] = VisitNumber;
418 }
419 }
420
421 for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
422 ModuleFile *CurrentModule = VisitOrder[I];
423 // Should we skip this module file?
424 if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
425 continue;
426
427 // Visit the module.
428 assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1)((void)0);
429 State->VisitNumber[CurrentModule->Index] = VisitNumber;
430 if (!Visitor(*CurrentModule))
431 continue;
432
433 // The visitor has requested that cut off visitation of any
434 // module that the current module depends on. To indicate this
435 // behavior, we mark all of the reachable modules as having been visited.
436 ModuleFile *NextModule = CurrentModule;
437 do {
438 // For any module that this module depends on, push it on the
439 // stack (if it hasn't already been marked as visited).
440 for (llvm::SetVector<ModuleFile *>::iterator
441 M = NextModule->Imports.begin(),
442 MEnd = NextModule->Imports.end();
443 M != MEnd; ++M) {
444 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
445 State->Stack.push_back(*M);
446 State->VisitNumber[(*M)->Index] = VisitNumber;
447 }
448 }
449
450 if (State->Stack.empty())
451 break;
452
453 // Pop the next module off the stack.
454 NextModule = State->Stack.pop_back_val();
455 } while (true);
456 }
457
458 returnVisitState(State);
459}
460
461bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize,
462 time_t ExpectedModTime,
463 Optional<FileEntryRef> &File) {
464 File = None;
465 if (FileName == "-")
16
Assuming the condition is true
17
Taking true branch
466 return false;
18
Returning without writing to 'File.Storage.MaybeRef.ME'
467
468 // Open the file immediately to ensure there is no race between stat'ing and
469 // opening the file.
470 Optional<FileEntryRef> FileOrErr =
471 expectedToOptional(FileMgr.getFileRef(FileName, /*OpenFile=*/true,
472 /*CacheFailure=*/false));
473 if (!FileOrErr)
474 return false;
475
476 File = *FileOrErr;
477
478 if ((ExpectedSize && ExpectedSize != File->getSize()) ||
479 (ExpectedModTime && ExpectedModTime != File->getModificationTime()))
480 // Do not destroy File, as it may be referenced. If we need to rebuild it,
481 // it will be destroyed by removeModules.
482 return true;
483
484 return false;
485}
486
487#ifndef NDEBUG1
488namespace llvm {
489
490 template<>
491 struct GraphTraits<ModuleManager> {
492 using NodeRef = ModuleFile *;
493 using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
494 using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
495
496 static ChildIteratorType child_begin(NodeRef Node) {
497 return Node->Imports.begin();
498 }
499
500 static ChildIteratorType child_end(NodeRef Node) {
501 return Node->Imports.end();
502 }
503
504 static nodes_iterator nodes_begin(const ModuleManager &Manager) {
505 return nodes_iterator(Manager.begin());
506 }
507
508 static nodes_iterator nodes_end(const ModuleManager &Manager) {
509 return nodes_iterator(Manager.end());
510 }
511 };
512
513 template<>
514 struct DOTGraphTraits<ModuleManager> : public DefaultDOTGraphTraits {
515 explicit DOTGraphTraits(bool IsSimple = false)
516 : DefaultDOTGraphTraits(IsSimple) {}
517
518 static bool renderGraphFromBottomUp() { return true; }
519
520 std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
521 return M->ModuleName;
522 }
523 };
524
525} // namespace llvm
526
527void ModuleManager::viewGraph() {
528 llvm::ViewGraph(*this, "Modules");
529}
530#endif

/usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/clang/include/clang/Basic/FileEntry.h

1//===- clang/Basic/FileEntry.h - File references ----------------*- C++ -*-===//
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/// \file
10/// Defines interfaces for clang::FileEntry and clang::FileEntryRef.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_BASIC_FILEENTRY_H
15#define LLVM_CLANG_BASIC_FILEENTRY_H
16
17#include "clang/Basic/DirectoryEntry.h"
18#include "clang/Basic/LLVM.h"
19#include "llvm/ADT/DenseMapInfo.h"
20#include "llvm/ADT/Hashing.h"
21#include "llvm/ADT/PointerUnion.h"
22#include "llvm/ADT/StringMap.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/Support/ErrorOr.h"
25#include "llvm/Support/FileSystem/UniqueID.h"
26
27namespace llvm {
28
29class MemoryBuffer;
30
31namespace vfs {
32
33class File;
34
35} // namespace vfs
36} // namespace llvm
37
38namespace clang {
39
40class FileEntryRef;
41
42} // namespace clang
43
44namespace llvm {
45namespace optional_detail {
46
47/// Forward declare a template specialization for OptionalStorage.
48template <>
49class OptionalStorage<clang::FileEntryRef, /*is_trivially_copyable*/ true>;
50
51} // namespace optional_detail
52} // namespace llvm
53
54namespace clang {
55
56class FileEntry;
57
58/// A reference to a \c FileEntry that includes the name of the file as it was
59/// accessed by the FileManager's client.
60class FileEntryRef {
61public:
62 StringRef getName() const { return ME->first(); }
63 const FileEntry &getFileEntry() const {
64 return *ME->second->V.get<FileEntry *>();
33
Called C++ object pointer is null
65 }
66 DirectoryEntryRef getDir() const { return *ME->second->Dir; }
67
68 inline bool isValid() const;
69 inline off_t getSize() const;
70 inline unsigned getUID() const;
71 inline const llvm::sys::fs::UniqueID &getUniqueID() const;
72 inline time_t getModificationTime() const;
73 inline bool isNamedPipe() const;
74 inline void closeFile() const;
75
76 /// Check if the underlying FileEntry is the same, intentially ignoring
77 /// whether the file was referenced with the same spelling of the filename.
78 friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
79 return &LHS.getFileEntry() == &RHS.getFileEntry();
80 }
81 friend bool operator==(const FileEntry *LHS, const FileEntryRef &RHS) {
82 return LHS == &RHS.getFileEntry();
83 }
84 friend bool operator==(const FileEntryRef &LHS, const FileEntry *RHS) {
85 return &LHS.getFileEntry() == RHS;
86 }
87 friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
88 return !(LHS == RHS);
89 }
90 friend bool operator!=(const FileEntry *LHS, const FileEntryRef &RHS) {
91 return !(LHS == RHS);
92 }
93 friend bool operator!=(const FileEntryRef &LHS, const FileEntry *RHS) {
94 return !(LHS == RHS);
95 }
96
97 /// Hash code is based on the FileEntry, not the specific named reference,
98 /// just like operator==.
99 friend llvm::hash_code hash_value(FileEntryRef Ref) {
100 return llvm::hash_value(&Ref.getFileEntry());
101 }
102
103 struct MapValue;
104
105 /// Type used in the StringMap.
106 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>;
107
108 /// Type stored in the StringMap.
109 struct MapValue {
110 /// The pointer at another MapEntry is used when the FileManager should
111 /// silently forward from one name to another, which occurs in Redirecting
112 /// VFSs that use external names. In that case, the \c FileEntryRef
113 /// returned by the \c FileManager will have the external name, and not the
114 /// name that was used to lookup the file.
115 ///
116 /// The second type is really a `const MapEntry *`, but that confuses
117 /// gcc5.3. Once that's no longer supported, change this back.
118 llvm::PointerUnion<FileEntry *, const void *> V;
119
120 /// Directory the file was found in. Set if and only if V is a FileEntry.
121 Optional<DirectoryEntryRef> Dir;
122
123 MapValue() = delete;
124 MapValue(FileEntry &FE, DirectoryEntryRef Dir) : V(&FE), Dir(Dir) {}
125 MapValue(MapEntry &ME) : V(&ME) {}
126 };
127
128 /// Check if RHS referenced the file in exactly the same way.
129 bool isSameRef(const FileEntryRef &RHS) const { return ME == RHS.ME; }
130
131 /// Allow FileEntryRef to degrade into 'const FileEntry*' to facilitate
132 /// incremental adoption.
133 ///
134 /// The goal is to avoid code churn due to dances like the following:
135 /// \code
136 /// // Old code.
137 /// lvalue = rvalue;
138 ///
139 /// // Temporary code from an incremental patch.
140 /// lvalue = &rvalue.getFileEntry();
141 ///
142 /// // Final code.
143 /// lvalue = rvalue;
144 /// \endcode
145 ///
146 /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
147 /// FileEntry::getName have been deleted, delete this implicit conversion.
148 operator const FileEntry *() const { return &getFileEntry(); }
149
150 FileEntryRef() = delete;
151 explicit FileEntryRef(const MapEntry &ME) : ME(&ME) {
152 assert(ME.second && "Expected payload")((void)0);
153 assert(ME.second->V && "Expected non-null")((void)0);
154 assert(ME.second->V.is<FileEntry *>() && "Expected FileEntry")((void)0);
155 }
156
157 /// Expose the underlying MapEntry to simplify packing in a PointerIntPair or
158 /// PointerUnion and allow construction in Optional.
159 const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; }
160
161private:
162 friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>;
163 struct optional_none_tag {};
164
165 // Private constructor for use by OptionalStorage.
166 FileEntryRef(optional_none_tag) : ME(nullptr) {}
6
Null pointer value stored to 'Entry.Storage.MaybeRef.ME'
167 bool hasOptionalValue() const { return ME; }
168
169 friend struct llvm::DenseMapInfo<FileEntryRef>;
170 struct dense_map_empty_tag {};
171 struct dense_map_tombstone_tag {};
172
173 // Private constructors for use by DenseMapInfo.
174 FileEntryRef(dense_map_empty_tag)
175 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
176 FileEntryRef(dense_map_tombstone_tag)
177 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
178 bool isSpecialDenseMapKey() const {
179 return isSameRef(FileEntryRef(dense_map_empty_tag())) ||
180 isSameRef(FileEntryRef(dense_map_tombstone_tag()));
181 }
182
183 const MapEntry *ME;
184};
185
186static_assert(sizeof(FileEntryRef) == sizeof(const FileEntry *),
187 "FileEntryRef must avoid size overhead");
188
189static_assert(std::is_trivially_copyable<FileEntryRef>::value,
190 "FileEntryRef must be trivially copyable");
191
192} // end namespace clang
193
194namespace llvm {
195namespace optional_detail {
196
197/// Customize OptionalStorage<FileEntryRef> to use FileEntryRef and its
198/// optional_none_tag to keep it the size of a single pointer.
199template <>
200class OptionalStorage<clang::FileEntryRef>
201 : public clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef> {
202 using StorageImpl =
203 clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef>;
204
205public:
206 OptionalStorage() = default;
4
Calling default constructor for 'MapEntryOptionalStorage<clang::FileEntryRef>'
8
Returning from default constructor for 'MapEntryOptionalStorage<clang::FileEntryRef>'
207
208 template <class... ArgTypes>
209 explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
210 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
211
212 OptionalStorage &operator=(clang::FileEntryRef Ref) {
213 StorageImpl::operator=(Ref);
214 return *this;
215 }
216};
217
218static_assert(sizeof(Optional<clang::FileEntryRef>) ==
219 sizeof(clang::FileEntryRef),
220 "Optional<FileEntryRef> must avoid size overhead");
221
222static_assert(std::is_trivially_copyable<Optional<clang::FileEntryRef>>::value,
223 "Optional<FileEntryRef> should be trivially copyable");
224
225} // end namespace optional_detail
226
227/// Specialisation of DenseMapInfo for FileEntryRef.
228template <> struct DenseMapInfo<clang::FileEntryRef> {
229 static inline clang::FileEntryRef getEmptyKey() {
230 return clang::FileEntryRef(clang::FileEntryRef::dense_map_empty_tag());
231 }
232
233 static inline clang::FileEntryRef getTombstoneKey() {
234 return clang::FileEntryRef(clang::FileEntryRef::dense_map_tombstone_tag());
235 }
236
237 static unsigned getHashValue(clang::FileEntryRef Val) {
238 return hash_value(Val);
239 }
240
241 static bool isEqual(clang::FileEntryRef LHS, clang::FileEntryRef RHS) {
242 // Catch the easy cases: both empty, both tombstone, or the same ref.
243 if (LHS.isSameRef(RHS))
244 return true;
245
246 // Confirm LHS and RHS are valid.
247 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
248 return false;
249
250 // It's safe to use operator==.
251 return LHS == RHS;
252 }
253};
254
255} // end namespace llvm
256
257namespace clang {
258
259/// Wrapper around Optional<FileEntryRef> that degrades to 'const FileEntry*',
260/// facilitating incremental patches to propagate FileEntryRef.
261///
262/// This class can be used as return value or field where it's convenient for
263/// an Optional<FileEntryRef> to degrade to a 'const FileEntry*'. The purpose
264/// is to avoid code churn due to dances like the following:
265/// \code
266/// // Old code.
267/// lvalue = rvalue;
268///
269/// // Temporary code from an incremental patch.
270/// Optional<FileEntryRef> MaybeF = rvalue;
271/// lvalue = MaybeF ? &MaybeF.getFileEntry() : nullptr;
272///
273/// // Final code.
274/// lvalue = rvalue;
275/// \endcode
276///
277/// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
278/// FileEntry::getName have been deleted, delete this class and replace
279/// instances with Optional<FileEntryRef>.
280class OptionalFileEntryRefDegradesToFileEntryPtr
281 : public Optional<FileEntryRef> {
282public:
283 OptionalFileEntryRefDegradesToFileEntryPtr() = default;
2
Calling default constructor for 'Optional<clang::FileEntryRef>'
10
Returning from default constructor for 'Optional<clang::FileEntryRef>'
284 OptionalFileEntryRefDegradesToFileEntryPtr(
285 OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
286 OptionalFileEntryRefDegradesToFileEntryPtr(
287 const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
288 OptionalFileEntryRefDegradesToFileEntryPtr &
289 operator=(OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
290 OptionalFileEntryRefDegradesToFileEntryPtr &
291 operator=(const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
292
293 OptionalFileEntryRefDegradesToFileEntryPtr(llvm::NoneType) {}
294 OptionalFileEntryRefDegradesToFileEntryPtr(FileEntryRef Ref)
295 : Optional<FileEntryRef>(Ref) {}
296 OptionalFileEntryRefDegradesToFileEntryPtr(Optional<FileEntryRef> MaybeRef)
297 : Optional<FileEntryRef>(MaybeRef) {}
298
299 OptionalFileEntryRefDegradesToFileEntryPtr &operator=(llvm::NoneType) {
300 Optional<FileEntryRef>::operator=(None);
301 return *this;
302 }
303 OptionalFileEntryRefDegradesToFileEntryPtr &operator=(FileEntryRef Ref) {
304 Optional<FileEntryRef>::operator=(Ref);
305 return *this;
306 }
307 OptionalFileEntryRefDegradesToFileEntryPtr &
308 operator=(Optional<FileEntryRef> MaybeRef) {
309 Optional<FileEntryRef>::operator=(MaybeRef);
310 return *this;
311 }
312
313 /// Degrade to 'const FileEntry *' to allow FileEntry::LastRef and
314 /// FileEntry::getName have been deleted, delete this class and replace
315 /// instances with Optional<FileEntryRef>
316 operator const FileEntry *() const {
317 return hasValue() ? &getValue().getFileEntry() : nullptr;
318 }
319};
320
321static_assert(
322 std::is_trivially_copyable<
323 OptionalFileEntryRefDegradesToFileEntryPtr>::value,
324 "OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable");
325
326/// Cached information about one file (either on disk
327/// or in the virtual file system).
328///
329/// If the 'File' member is valid, then this FileEntry has an open file
330/// descriptor for the file.
331class FileEntry {
332 friend class FileManager;
333
334 std::string RealPathName; // Real path to the file; could be empty.
335 off_t Size = 0; // File size in bytes.
336 time_t ModTime = 0; // Modification time of file.
337 const DirectoryEntry *Dir = nullptr; // Directory file lives in.
338 llvm::sys::fs::UniqueID UniqueID;
339 unsigned UID = 0; // A unique (small) ID for the file.
340 bool IsNamedPipe = false;
341 bool IsValid = false; // Is this \c FileEntry initialized and valid?
342
343 /// The open file, if it is owned by the \p FileEntry.
344 mutable std::unique_ptr<llvm::vfs::File> File;
345
346 /// The file content, if it is owned by the \p FileEntry.
347 std::unique_ptr<llvm::MemoryBuffer> Content;
348
349 // First access name for this FileEntry.
350 //
351 // This is Optional only to allow delayed construction (FileEntryRef has no
352 // default constructor). It should always have a value in practice.
353 //
354 // TODO: remove this once everyone that needs a name uses FileEntryRef.
355 Optional<FileEntryRef> LastRef;
356
357public:
358 FileEntry();
359 ~FileEntry();
360
361 FileEntry(const FileEntry &) = delete;
362 FileEntry &operator=(const FileEntry &) = delete;
363
364 StringRef getName() const { return LastRef->getName(); }
365 FileEntryRef getLastRef() const { return *LastRef; }
366
367 StringRef tryGetRealPathName() const { return RealPathName; }
368 bool isValid() const { return IsValid; }
369 off_t getSize() const { return Size; }
370 unsigned getUID() const { return UID; }
371 const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
372 time_t getModificationTime() const { return ModTime; }
373
374 /// Return the directory the file lives in.
375 const DirectoryEntry *getDir() const { return Dir; }
376
377 bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; }
378
379 /// Check whether the file is a named pipe (and thus can't be opened by
380 /// the native FileManager methods).
381 bool isNamedPipe() const { return IsNamedPipe; }
382
383 void closeFile() const;
384};
385
386bool FileEntryRef::isValid() const { return getFileEntry().isValid(); }
387
388off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); }
389
390unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); }
391
392const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const {
393 return getFileEntry().getUniqueID();
394}
395
396time_t FileEntryRef::getModificationTime() const {
397 return getFileEntry().getModificationTime();
398}
399
400bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); }
401
402void FileEntryRef::closeFile() const { getFileEntry().closeFile(); }
32
Calling 'FileEntryRef::getFileEntry'
403
404} // end namespace clang
405
406#endif // LLVM_CLANG_BASIC_FILEENTRY_H

/usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/llvm/include/llvm/ADT/Optional.h

1//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
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// This file provides Optional, a template class modeled in the spirit of
10// OCaml's 'opt' variant. The idea is to strongly type whether or not
11// a value can be optional.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_OPTIONAL_H
16#define LLVM_ADT_OPTIONAL_H
17
18#include "llvm/ADT/Hashing.h"
19#include "llvm/ADT/None.h"
20#include "llvm/ADT/STLForwardCompat.h"
21#include "llvm/Support/Compiler.h"
22#include "llvm/Support/type_traits.h"
23#include <cassert>
24#include <memory>
25#include <new>
26#include <utility>
27
28namespace llvm {
29
30class raw_ostream;
31
32namespace optional_detail {
33
34/// Storage for any type.
35//
36// The specialization condition intentionally uses
37// llvm::is_trivially_copy_constructible instead of
38// std::is_trivially_copy_constructible. GCC versions prior to 7.4 may
39// instantiate the copy constructor of `T` when
40// std::is_trivially_copy_constructible is instantiated. This causes
41// compilation to fail if we query the trivially copy constructible property of
42// a class which is not copy constructible.
43//
44// The current implementation of OptionalStorage insists that in order to use
45// the trivial specialization, the value_type must be trivially copy
46// constructible and trivially copy assignable due to =default implementations
47// of the copy/move constructor/assignment. It does not follow that this is
48// necessarily the case std::is_trivially_copyable is true (hence the expanded
49// specialization condition).
50//
51// The move constructible / assignable conditions emulate the remaining behavior
52// of std::is_trivially_copyable.
53template <typename T, bool = (llvm::is_trivially_copy_constructible<T>::value &&
54 std::is_trivially_copy_assignable<T>::value &&
55 (std::is_trivially_move_constructible<T>::value ||
56 !std::is_move_constructible<T>::value) &&
57 (std::is_trivially_move_assignable<T>::value ||
58 !std::is_move_assignable<T>::value))>
59class OptionalStorage {
60 union {
61 char empty;
62 T value;
63 };
64 bool hasVal;
65
66public:
67 ~OptionalStorage() { reset(); }
68
69 constexpr OptionalStorage() noexcept : empty(), hasVal(false) {}
70
71 constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
72 if (other.hasValue()) {
73 emplace(other.value);
74 }
75 }
76 constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
77 if (other.hasValue()) {
78 emplace(std::move(other.value));
79 }
80 }
81
82 template <class... Args>
83 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
84 : value(std::forward<Args>(args)...), hasVal(true) {}
85
86 void reset() noexcept {
87 if (hasVal) {
88 value.~T();
89 hasVal = false;
90 }
91 }
92
93 constexpr bool hasValue() const noexcept { return hasVal; }
94
95 T &getValue() LLVM_LVALUE_FUNCTION& noexcept {
96 assert(hasVal)((void)0);
97 return value;
98 }
99 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept {
100 assert(hasVal)((void)0);
101 return value;
102 }
103#if LLVM_HAS_RVALUE_REFERENCE_THIS1
104 T &&getValue() && noexcept {
105 assert(hasVal)((void)0);
106 return std::move(value);
107 }
108#endif
109
110 template <class... Args> void emplace(Args &&... args) {
111 reset();
112 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
113 hasVal = true;
114 }
115
116 OptionalStorage &operator=(T const &y) {
117 if (hasValue()) {
118 value = y;
119 } else {
120 ::new ((void *)std::addressof(value)) T(y);
121 hasVal = true;
122 }
123 return *this;
124 }
125 OptionalStorage &operator=(T &&y) {
126 if (hasValue()) {
127 value = std::move(y);
128 } else {
129 ::new ((void *)std::addressof(value)) T(std::move(y));
130 hasVal = true;
131 }
132 return *this;
133 }
134
135 OptionalStorage &operator=(OptionalStorage const &other) {
136 if (other.hasValue()) {
137 if (hasValue()) {
138 value = other.value;
139 } else {
140 ::new ((void *)std::addressof(value)) T(other.value);
141 hasVal = true;
142 }
143 } else {
144 reset();
145 }
146 return *this;
147 }
148
149 OptionalStorage &operator=(OptionalStorage &&other) {
150 if (other.hasValue()) {
151 if (hasValue()) {
152 value = std::move(other.value);
153 } else {
154 ::new ((void *)std::addressof(value)) T(std::move(other.value));
155 hasVal = true;
156 }
157 } else {
158 reset();
159 }
160 return *this;
161 }
162};
163
164template <typename T> class OptionalStorage<T, true> {
165 union {
166 char empty;
167 T value;
168 };
169 bool hasVal = false;
170
171public:
172 ~OptionalStorage() = default;
173
174 constexpr OptionalStorage() noexcept : empty{} {}
175
176 constexpr OptionalStorage(OptionalStorage const &other) = default;
177 constexpr OptionalStorage(OptionalStorage &&other) = default;
178
179 OptionalStorage &operator=(OptionalStorage const &other) = default;
180 OptionalStorage &operator=(OptionalStorage &&other) = default;
181
182 template <class... Args>
183 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
184 : value(std::forward<Args>(args)...), hasVal(true) {}
185
186 void reset() noexcept {
187 if (hasVal) {
188 value.~T();
189 hasVal = false;
190 }
191 }
192
193 constexpr bool hasValue() const noexcept { return hasVal; }
194
195 T &getValue() LLVM_LVALUE_FUNCTION& noexcept {
196 assert(hasVal)((void)0);
197 return value;
198 }
199 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept {
200 assert(hasVal)((void)0);
201 return value;
202 }
203#if LLVM_HAS_RVALUE_REFERENCE_THIS1
204 T &&getValue() && noexcept {
205 assert(hasVal)((void)0);
206 return std::move(value);
207 }
208#endif
209
210 template <class... Args> void emplace(Args &&... args) {
211 reset();
212 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
213 hasVal = true;
214 }
215
216 OptionalStorage &operator=(T const &y) {
217 if (hasValue()) {
218 value = y;
219 } else {
220 ::new ((void *)std::addressof(value)) T(y);
221 hasVal = true;
222 }
223 return *this;
224 }
225 OptionalStorage &operator=(T &&y) {
226 if (hasValue()) {
227 value = std::move(y);
228 } else {
229 ::new ((void *)std::addressof(value)) T(std::move(y));
230 hasVal = true;
231 }
232 return *this;
233 }
234};
235
236} // namespace optional_detail
237
238template <typename T> class Optional {
239 optional_detail::OptionalStorage<T> Storage;
240
241public:
242 using value_type = T;
243
244 constexpr Optional() {}
3
Calling defaulted default constructor for 'OptionalStorage<clang::FileEntryRef, true>'
9
Returning from default constructor for 'OptionalStorage<clang::FileEntryRef, true>'
245 constexpr Optional(NoneType) {}
246
247 constexpr Optional(const T &y) : Storage(in_place, y) {}
248 constexpr Optional(const Optional &O) = default;
249
250 constexpr Optional(T &&y) : Storage(in_place, std::move(y)) {}
251 constexpr Optional(Optional &&O) = default;
252
253 template <typename... ArgTypes>
254 constexpr Optional(in_place_t, ArgTypes &&...Args)
255 : Storage(in_place, std::forward<ArgTypes>(Args)...) {}
256
257 Optional &operator=(T &&y) {
258 Storage = std::move(y);
259 return *this;
260 }
261 Optional &operator=(Optional &&O) = default;
262
263 /// Create a new object by constructing it in place with the given arguments.
264 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
265 Storage.emplace(std::forward<ArgTypes>(Args)...);
266 }
267
268 static constexpr Optional create(const T *y) {
269 return y ? Optional(*y) : Optional();
270 }
271
272 Optional &operator=(const T &y) {
273 Storage = y;
274 return *this;
275 }
276 Optional &operator=(const Optional &O) = default;
277
278 void reset() { Storage.reset(); }
279
280 constexpr const T *getPointer() const { return &Storage.getValue(); }
281 T *getPointer() { return &Storage.getValue(); }
282 constexpr const T &getValue() const LLVM_LVALUE_FUNCTION& {
283 return Storage.getValue();
284 }
285 T &getValue() LLVM_LVALUE_FUNCTION& { return Storage.getValue(); }
286
287 constexpr explicit operator bool() const { return hasValue(); }
288 constexpr bool hasValue() const { return Storage.hasValue(); }
289 constexpr const T *operator->() const { return getPointer(); }
290 T *operator->() { return getPointer(); }
291 constexpr const T &operator*() const LLVM_LVALUE_FUNCTION& {
292 return getValue();
293 }
294 T &operator*() LLVM_LVALUE_FUNCTION& { return getValue(); }
295
296 template <typename U>
297 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION& {
298 return hasValue() ? getValue() : std::forward<U>(value);
299 }
300
301 /// Apply a function to the value if present; otherwise return None.
302 template <class Function>
303 auto map(const Function &F) const LLVM_LVALUE_FUNCTION&
304 -> Optional<decltype(F(getValue()))> {
305 if (*this) return F(getValue());
306 return None;
307 }
308
309#if LLVM_HAS_RVALUE_REFERENCE_THIS1
310 T &&getValue() && { return std::move(Storage.getValue()); }
311 T &&operator*() && { return std::move(Storage.getValue()); }
312
313 template <typename U>
314 T getValueOr(U &&value) && {
315 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
316 }
317
318 /// Apply a function to the value if present; otherwise return None.
319 template <class Function>
320 auto map(const Function &F) &&
321 -> Optional<decltype(F(std::move(*this).getValue()))> {
322 if (*this) return F(std::move(*this).getValue());
323 return None;
324 }
325#endif
326};
327
328template <class T> llvm::hash_code hash_value(const Optional<T> &O) {
329 return O ? hash_combine(true, *O) : hash_value(false);
330}
331
332template <typename T, typename U>
333constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) {
334 if (X && Y)
335 return *X == *Y;
336 return X.hasValue() == Y.hasValue();
337}
338
339template <typename T, typename U>
340constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
341 return !(X == Y);
342}
343
344template <typename T, typename U>
345constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) {
346 if (X && Y)
347 return *X < *Y;
348 return X.hasValue() < Y.hasValue();
349}
350
351template <typename T, typename U>
352constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
353 return !(Y < X);
354}
355
356template <typename T, typename U>
357constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) {
358 return Y < X;
359}
360
361template <typename T, typename U>
362constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
363 return !(X < Y);
364}
365
366template <typename T>
367constexpr bool operator==(const Optional<T> &X, NoneType) {
368 return !X;
369}
370
371template <typename T>
372constexpr bool operator==(NoneType, const Optional<T> &X) {
373 return X == None;
374}
375
376template <typename T>
377constexpr bool operator!=(const Optional<T> &X, NoneType) {
378 return !(X == None);
379}
380
381template <typename T>
382constexpr bool operator!=(NoneType, const Optional<T> &X) {
383 return X != None;
384}
385
386template <typename T> constexpr bool operator<(const Optional<T> &, NoneType) {
387 return false;
388}
389
390template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) {
391 return X.hasValue();
392}
393
394template <typename T>
395constexpr bool operator<=(const Optional<T> &X, NoneType) {
396 return !(None < X);
397}
398
399template <typename T>
400constexpr bool operator<=(NoneType, const Optional<T> &X) {
401 return !(X < None);
402}
403
404template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) {
405 return None < X;
406}
407
408template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) {
409 return X < None;
410}
411
412template <typename T>
413constexpr bool operator>=(const Optional<T> &X, NoneType) {
414 return None <= X;
415}
416
417template <typename T>
418constexpr bool operator>=(NoneType, const Optional<T> &X) {
419 return X <= None;
420}
421
422template <typename T>
423constexpr bool operator==(const Optional<T> &X, const T &Y) {
424 return X && *X == Y;
425}
426
427template <typename T>
428constexpr bool operator==(const T &X, const Optional<T> &Y) {
429 return Y && X == *Y;
430}
431
432template <typename T>
433constexpr bool operator!=(const Optional<T> &X, const T &Y) {
434 return !(X == Y);
435}
436
437template <typename T>
438constexpr bool operator!=(const T &X, const Optional<T> &Y) {
439 return !(X == Y);
440}
441
442template <typename T>
443constexpr bool operator<(const Optional<T> &X, const T &Y) {
444 return !X || *X < Y;
445}
446
447template <typename T>
448constexpr bool operator<(const T &X, const Optional<T> &Y) {
449 return Y && X < *Y;
450}
451
452template <typename T>
453constexpr bool operator<=(const Optional<T> &X, const T &Y) {
454 return !(Y < X);
455}
456
457template <typename T>
458constexpr bool operator<=(const T &X, const Optional<T> &Y) {
459 return !(Y < X);
460}
461
462template <typename T>
463constexpr bool operator>(const Optional<T> &X, const T &Y) {
464 return Y < X;
465}
466
467template <typename T>
468constexpr bool operator>(const T &X, const Optional<T> &Y) {
469 return Y < X;
470}
471
472template <typename T>
473constexpr bool operator>=(const Optional<T> &X, const T &Y) {
474 return !(X < Y);
475}
476
477template <typename T>
478constexpr bool operator>=(const T &X, const Optional<T> &Y) {
479 return !(X < Y);
480}
481
482raw_ostream &operator<<(raw_ostream &OS, NoneType);
483
484template <typename T, typename = decltype(std::declval<raw_ostream &>()
485 << std::declval<const T &>())>
486raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
487 if (O)
488 OS << *O;
489 else
490 OS << None;
491 return OS;
492}
493
494} // end namespace llvm
495
496#endif // LLVM_ADT_OPTIONAL_H

/usr/src/gnu/usr.bin/clang/libclangSerialization/../../../llvm/clang/include/clang/Basic/DirectoryEntry.h

1//===- clang/Basic/DirectoryEntry.h - Directory references ------*- C++ -*-===//
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/// \file
10/// Defines interfaces for clang::DirectoryEntry and clang::DirectoryEntryRef.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_BASIC_DIRECTORYENTRY_H
15#define LLVM_CLANG_BASIC_DIRECTORYENTRY_H
16
17#include "clang/Basic/LLVM.h"
18#include "llvm/ADT/DenseMapInfo.h"
19#include "llvm/ADT/Hashing.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/ErrorOr.h"
23
24namespace clang {
25namespace FileMgr {
26
27template <class RefTy> class MapEntryOptionalStorage;
28
29} // end namespace FileMgr
30
31/// Cached information about one directory (either on disk or in
32/// the virtual file system).
33class DirectoryEntry {
34 friend class FileManager;
35
36 // FIXME: We should not be storing a directory entry name here.
37 StringRef Name; // Name of the directory.
38
39public:
40 StringRef getName() const { return Name; }
41};
42
43/// A reference to a \c DirectoryEntry that includes the name of the directory
44/// as it was accessed by the FileManager's client.
45class DirectoryEntryRef {
46public:
47 const DirectoryEntry &getDirEntry() const { return *ME->getValue(); }
48
49 StringRef getName() const { return ME->getKey(); }
50
51 /// Hash code is based on the DirectoryEntry, not the specific named
52 /// reference.
53 friend llvm::hash_code hash_value(DirectoryEntryRef Ref) {
54 return llvm::hash_value(&Ref.getDirEntry());
55 }
56
57 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>;
58
59 const MapEntry &getMapEntry() const { return *ME; }
60
61 /// Check if RHS referenced the file in exactly the same way.
62 bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; }
63
64 DirectoryEntryRef() = delete;
65 DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {}
66
67 /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to
68 /// facilitate incremental adoption.
69 ///
70 /// The goal is to avoid code churn due to dances like the following:
71 /// \code
72 /// // Old code.
73 /// lvalue = rvalue;
74 ///
75 /// // Temporary code from an incremental patch.
76 /// lvalue = &rvalue.getDirectoryEntry();
77 ///
78 /// // Final code.
79 /// lvalue = rvalue;
80 /// \endcode
81 ///
82 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName
83 /// has been deleted, delete this implicit conversion.
84 operator const DirectoryEntry *() const { return &getDirEntry(); }
85
86private:
87 friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>;
88 struct optional_none_tag {};
89
90 // Private constructor for use by OptionalStorage.
91 DirectoryEntryRef(optional_none_tag) : ME(nullptr) {}
92 bool hasOptionalValue() const { return ME; }
93
94 friend struct llvm::DenseMapInfo<DirectoryEntryRef>;
95 struct dense_map_empty_tag {};
96 struct dense_map_tombstone_tag {};
97
98 // Private constructors for use by DenseMapInfo.
99 DirectoryEntryRef(dense_map_empty_tag)
100 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
101 DirectoryEntryRef(dense_map_tombstone_tag)
102 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
103 bool isSpecialDenseMapKey() const {
104 return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) ||
105 isSameRef(DirectoryEntryRef(dense_map_tombstone_tag()));
106 }
107
108 const MapEntry *ME;
109};
110
111namespace FileMgr {
112
113/// Customized storage for refs derived from map entires in FileManager, using
114/// the private optional_none_tag to keep it to the size of a single pointer.
115template <class RefTy> class MapEntryOptionalStorage {
116 using optional_none_tag = typename RefTy::optional_none_tag;
117 RefTy MaybeRef;
118
119public:
120 MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {}
5
Calling constructor for 'FileEntryRef'
7
Returning from constructor for 'FileEntryRef'
121
122 template <class... ArgTypes>
123 explicit MapEntryOptionalStorage(llvm::in_place_t, ArgTypes &&...Args)
124 : MaybeRef(std::forward<ArgTypes>(Args)...) {}
125
126 void reset() { MaybeRef = optional_none_tag(); }
127
128 bool hasValue() const { return MaybeRef.hasOptionalValue(); }
129
130 RefTy &getValue() LLVM_LVALUE_FUNCTION& {
131 assert(hasValue())((void)0);
132 return MaybeRef;
133 }
134 RefTy const &getValue() const LLVM_LVALUE_FUNCTION& {
135 assert(hasValue())((void)0);
136 return MaybeRef;
137 }
138#if LLVM_HAS_RVALUE_REFERENCE_THIS1
139 RefTy &&getValue() && {
140 assert(hasValue())((void)0);
141 return std::move(MaybeRef);
142 }
143#endif
144
145 template <class... Args> void emplace(Args &&...args) {
146 MaybeRef = RefTy(std::forward<Args>(args)...);
147 }
148
149 MapEntryOptionalStorage &operator=(RefTy Ref) {
150 MaybeRef = Ref;
151 return *this;
152 }
153};
154
155} // end namespace FileMgr
156} // end namespace clang
157
158namespace llvm {
159namespace optional_detail {
160
161/// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and
162/// its optional_none_tag to keep it the size of a single pointer.
163template <>
164class OptionalStorage<clang::DirectoryEntryRef>
165 : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> {
166 using StorageImpl =
167 clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>;
168
169public:
170 OptionalStorage() = default;
171
172 template <class... ArgTypes>
173 explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
174 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
175
176 OptionalStorage &operator=(clang::DirectoryEntryRef Ref) {
177 StorageImpl::operator=(Ref);
178 return *this;
179 }
180};
181
182static_assert(sizeof(Optional<clang::DirectoryEntryRef>) ==
183 sizeof(clang::DirectoryEntryRef),
184 "Optional<DirectoryEntryRef> must avoid size overhead");
185
186static_assert(
187 std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value,
188 "Optional<DirectoryEntryRef> should be trivially copyable");
189
190} // end namespace optional_detail
191
192/// Specialisation of DenseMapInfo for DirectoryEntryRef.
193template <> struct DenseMapInfo<clang::DirectoryEntryRef> {
194 static inline clang::DirectoryEntryRef getEmptyKey() {
195 return clang::DirectoryEntryRef(
196 clang::DirectoryEntryRef::dense_map_empty_tag());
197 }
198
199 static inline clang::DirectoryEntryRef getTombstoneKey() {
200 return clang::DirectoryEntryRef(
201 clang::DirectoryEntryRef::dense_map_tombstone_tag());
202 }
203
204 static unsigned getHashValue(clang::DirectoryEntryRef Val) {
205 return hash_value(Val);
206 }
207
208 static bool isEqual(clang::DirectoryEntryRef LHS,
209 clang::DirectoryEntryRef RHS) {
210 // Catch the easy cases: both empty, both tombstone, or the same ref.
211 if (LHS.isSameRef(RHS))
212 return true;
213
214 // Confirm LHS and RHS are valid.
215 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
216 return false;
217
218 // It's safe to use operator==.
219 return LHS == RHS;
220 }
221};
222
223} // end namespace llvm
224
225namespace clang {
226
227/// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const
228/// DirectoryEntry*', facilitating incremental patches to propagate
229/// DirectoryEntryRef.
230///
231/// This class can be used as return value or field where it's convenient for
232/// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The
233/// purpose is to avoid code churn due to dances like the following:
234/// \code
235/// // Old code.
236/// lvalue = rvalue;
237///
238/// // Temporary code from an incremental patch.
239/// Optional<DirectoryEntryRef> MaybeF = rvalue;
240/// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr;
241///
242/// // Final code.
243/// lvalue = rvalue;
244/// \endcode
245///
246/// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef
247/// and DirectoryEntry::getName have been deleted, delete this class and
248/// replace instances with Optional<DirectoryEntryRef>.
249class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr
250 : public Optional<DirectoryEntryRef> {
251public:
252 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default;
253 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
254 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
255 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
256 const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
257 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
258 operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
259 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
260 operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
261
262 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {}
263 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref)
264 : Optional<DirectoryEntryRef>(Ref) {}
265 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef)
266 : Optional<DirectoryEntryRef>(MaybeRef) {}
267
268 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) {
269 Optional<DirectoryEntryRef>::operator=(None);
270 return *this;
271 }
272 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) {
273 Optional<DirectoryEntryRef>::operator=(Ref);
274 return *this;
275 }
276 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
277 operator=(Optional<DirectoryEntryRef> MaybeRef) {
278 Optional<DirectoryEntryRef>::operator=(MaybeRef);
279 return *this;
280 }
281
282 /// Degrade to 'const DirectoryEntry *' to allow DirectoryEntry::LastRef and
283 /// DirectoryEntry::getName have been deleted, delete this class and replace
284 /// instances with Optional<DirectoryEntryRef>
285 operator const DirectoryEntry *() const {
286 return hasValue() ? &getValue().getDirEntry() : nullptr;
287 }
288};
289
290static_assert(std::is_trivially_copyable<
291 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value,
292 "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be "
293 "trivially copyable");
294
295} // end namespace clang
296
297#endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H