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
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 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 | |
| 41 | using namespace clang; |
| 42 | using namespace serialization; |
| 43 | |
| 44 | ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const { |
| 45 | auto Entry = FileMgr.getFile(Name, false, |
| 46 | false); |
| 47 | if (Entry) |
| 48 | return lookup(*Entry); |
| 49 | |
| 50 | return nullptr; |
| 51 | } |
| 52 | |
| 53 | ModuleFile *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 | |
| 61 | ModuleFile *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 | |
| 69 | std::unique_ptr<llvm::MemoryBuffer> |
| 70 | ModuleManager::lookupBuffer(StringRef Name) { |
| 71 | auto Entry = FileMgr.getFile(Name, false, |
| 72 | false); |
| 73 | if (!Entry) |
| 74 | return nullptr; |
| 75 | return std::move(InMemoryBuffers[*Entry]); |
| 76 | } |
| 77 | |
| 78 | static 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 | |
| 89 | static 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 | |
| 102 | ModuleManager::AddModuleResult |
| 103 | ModuleManager::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 | |
| 114 | |
| 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 | |
|
| |
| 117 | |
| 118 | |
| 119 | |
| 120 | |
| 121 | ExpectedModTime = 0; |
| 122 | } |
| 123 | |
| 124 | |
| 125 | if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry)) { |
| 15 | | Calling 'ModuleManager::lookupModuleFile' | |
|
| 19 | | Returning from 'ModuleManager::lookupModuleFile' | |
|
| |
| 126 | ErrorStr = "module file out of date"; |
| 127 | return OutOfDate; |
| 128 | } |
| 129 | |
| 130 | if (!Entry && FileName != "-") { |
| |
| 131 | ErrorStr = "module file not found"; |
| 132 | return Missing; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | |
| 137 | |
| 138 | |
| 139 | |
| 140 | |
| 141 | |
| 142 | |
| 143 | |
| 144 | |
| 145 | |
| 146 | |
| 147 | |
| 148 | |
| 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 | |
| 157 | if (ModuleFile *ModuleEntry = Modules.lookup(Entry)) { |
| 22 | | Assuming 'ModuleEntry' is null | |
|
| |
| 158 | if (implicitModuleNamesMatch(Type, ModuleEntry, Entry)) { |
| 159 | |
| 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 | |
| 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 | |
|
| |
| 178 | std::string TimestampFilename = NewModule->getTimestampFilename(); |
| 179 | llvm::vfs::Status Status; |
| 180 | |
| 181 | if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status)) |
| 182 | NewModule->InputFilesValidationTimestamp = |
| 183 | llvm::sys::toTimeT(Status.getLastModificationTime()); |
| 184 | } |
| 185 | |
| 186 | |
| 187 | if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) { |
| |
| 188 | |
| 189 | NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer)); |
| 190 | |
| 191 | |
| 192 | |
| 193 | Entry->closeFile(); |
| 194 | } else if (llvm::MemoryBuffer *Buffer = |
| 27 | | Assuming 'Buffer' is null | |
|
| |
| 195 | getModuleCache().lookupPCM(FileName)) { |
| 196 | NewModule->Buffer = Buffer; |
| 197 | |
| 198 | Entry->closeFile(); |
| 199 | } else if (getModuleCache().shouldBuildPCM(FileName)) { |
| 29 | | Assuming the condition is true | |
|
| |
| 200 | |
| 201 | |
| 202 | Entry->closeFile(); |
| 31 | | Calling 'FileEntryRef::closeFile' | |
|
| 203 | return OutOfDate; |
| 204 | } else { |
| 205 | |
| 206 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code())); |
| 207 | if (FileName == "-") { |
| 208 | Buf = llvm::MemoryBuffer::getSTDIN(); |
| 209 | } else { |
| 210 | |
| 211 | |
| 212 | |
| 213 | |
| 214 | |
| 215 | |
| 216 | Buf = FileMgr.getBufferForFile(NewModule->File, |
| 217 | true, |
| 218 | 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 | |
| 230 | NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer); |
| 231 | |
| 232 | |
| 233 | |
| 234 | if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data), |
| 235 | ExpectedSignature, ErrorStr)) |
| 236 | return OutOfDate; |
| 237 | |
| 238 | |
| 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 | |
| 252 | void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) { |
| 253 | auto Last = end(); |
| 254 | if (First == Last) |
| 255 | return; |
| 256 | |
| 257 | |
| 258 | VisitOrder.clear(); |
| 259 | |
| 260 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 297 | Chain.erase(Chain.begin() + (First - begin()), Chain.end()); |
| 298 | } |
| 299 | |
| 300 | void |
| 301 | ModuleManager::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 | |
| 308 | ModuleManager::VisitState *ModuleManager::allocateVisitState() { |
| 309 | |
| 310 | if (FirstVisitState) { |
| 311 | VisitState *Result = FirstVisitState; |
| 312 | FirstVisitState = FirstVisitState->NextState; |
| 313 | Result->NextState = nullptr; |
| 314 | return Result; |
| 315 | } |
| 316 | |
| 317 | |
| 318 | return new VisitState(size()); |
| 319 | } |
| 320 | |
| 321 | void ModuleManager::returnVisitState(VisitState *State) { |
| 322 | assert(State->NextState == nullptr && "Visited state is in list?"); |
| 323 | State->NextState = FirstVisitState; |
| 324 | FirstVisitState = State; |
| 325 | } |
| 326 | |
| 327 | void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) { |
| 328 | GlobalIndex = Index; |
| 329 | if (!GlobalIndex) { |
| 330 | ModulesInCommonWithGlobalIndex.clear(); |
| 331 | return; |
| 332 | } |
| 333 | |
| 334 | |
| 335 | |
| 336 | for (ModuleFile &M : *this) |
| 337 | if (!GlobalIndex->loadedModuleFile(&M)) |
| 338 | ModulesInCommonWithGlobalIndex.push_back(&M); |
| 339 | } |
| 340 | |
| 341 | void ModuleManager::moduleFileAccepted(ModuleFile *MF) { |
| 342 | if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF)) |
| 343 | return; |
| 344 | |
| 345 | ModulesInCommonWithGlobalIndex.push_back(MF); |
| 346 | } |
| 347 | |
| 348 | ModuleManager::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 | |
| 355 | ModuleManager::~ModuleManager() { delete FirstVisitState; } |
| 356 | |
| 357 | void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor, |
| 358 | llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) { |
| 359 | |
| 360 | if (VisitOrder.size() != Chain.size()) { |
| 361 | unsigned N = size(); |
| 362 | VisitOrder.clear(); |
| 363 | VisitOrder.reserve(N); |
| 364 | |
| 365 | |
| 366 | |
| 367 | |
| 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 | |
| 380 | |
| 381 | while (!Queue.empty()) { |
| 382 | ModuleFile *CurrentModule = Queue.pop_back_val(); |
| 383 | VisitOrder.push_back(CurrentModule); |
| 384 | |
| 385 | |
| 386 | |
| 387 | for (auto M = CurrentModule->Imports.rbegin(), |
| 388 | MEnd = CurrentModule->Imports.rend(); |
| 389 | M != MEnd; ++M) { |
| 390 | |
| 391 | |
| 392 | |
| 393 | |
| 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?"); |
| 401 | |
| 402 | delete FirstVisitState; |
| 403 | FirstVisitState = nullptr; |
| 404 | } |
| 405 | |
| 406 | VisitState *State = allocateVisitState(); |
| 407 | unsigned VisitNumber = State->NextVisitNumber++; |
| 408 | |
| 409 | |
| 410 | |
| 411 | |
| 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 | |
| 424 | if (State->VisitNumber[CurrentModule->Index] == VisitNumber) |
| 425 | continue; |
| 426 | |
| 427 | |
| 428 | assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1); |
| 429 | State->VisitNumber[CurrentModule->Index] = VisitNumber; |
| 430 | if (!Visitor(*CurrentModule)) |
| 431 | continue; |
| 432 | |
| 433 | |
| 434 | |
| 435 | |
| 436 | ModuleFile *NextModule = CurrentModule; |
| 437 | do { |
| 438 | |
| 439 | |
| 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 | |
| 454 | NextModule = State->Stack.pop_back_val(); |
| 455 | } while (true); |
| 456 | } |
| 457 | |
| 458 | returnVisitState(State); |
| 459 | } |
| 460 | |
| 461 | bool 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 | |
|
| |
| 466 | return false; |
| 18 | | Returning without writing to 'File.Storage.MaybeRef.ME' | |
|
| 467 | |
| 468 | |
| 469 | |
| 470 | Optional<FileEntryRef> FileOrErr = |
| 471 | expectedToOptional(FileMgr.getFileRef(FileName, true, |
| 472 | false)); |
| 473 | if (!FileOrErr) |
| 474 | return false; |
| 475 | |
| 476 | File = *FileOrErr; |
| 477 | |
| 478 | if ((ExpectedSize && ExpectedSize != File->getSize()) || |
| 479 | (ExpectedModTime && ExpectedModTime != File->getModificationTime())) |
| 480 | |
| 481 | |
| 482 | return true; |
| 483 | |
| 484 | return false; |
| 485 | } |
| 486 | |
| 487 | #ifndef NDEBUG |
| 488 | namespace 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 | } |
| 526 | |
| 527 | void ModuleManager::viewGraph() { |
| 528 | llvm::ViewGraph(*this, "Modules"); |
| 529 | } |
| 530 | #endif |
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 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 | |
| 27 | namespace llvm { |
| 28 | |
| 29 | class MemoryBuffer; |
| 30 | |
| 31 | namespace vfs { |
| 32 | |
| 33 | class File; |
| 34 | |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | namespace clang { |
| 39 | |
| 40 | class FileEntryRef; |
| 41 | |
| 42 | } |
| 43 | |
| 44 | namespace llvm { |
| 45 | namespace optional_detail { |
| 46 | |
| 47 | |
| 48 | template <> |
| 49 | class OptionalStorage<clang::FileEntryRef, true>; |
| 50 | |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | namespace clang { |
| 55 | |
| 56 | class FileEntry; |
| 57 | |
| 58 | |
| 59 | |
| 60 | class FileEntryRef { |
| 61 | public: |
| 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 | |
| 77 | |
| 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 | |
| 98 | |
| 99 | friend llvm::hash_code hash_value(FileEntryRef Ref) { |
| 100 | return llvm::hash_value(&Ref.getFileEntry()); |
| 101 | } |
| 102 | |
| 103 | struct MapValue; |
| 104 | |
| 105 | |
| 106 | using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>; |
| 107 | |
| 108 | |
| 109 | struct MapValue { |
| 110 | |
| 111 | |
| 112 | |
| 113 | |
| 114 | |
| 115 | |
| 116 | |
| 117 | |
| 118 | llvm::PointerUnion<FileEntry *, const void *> V; |
| 119 | |
| 120 | |
| 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 | |
| 129 | bool isSameRef(const FileEntryRef &RHS) const { return ME == RHS.ME; } |
| 130 | |
| 131 | |
| 132 | |
| 133 | |
| 134 | |
| 135 | |
| 136 | |
| 137 | |
| 138 | |
| 139 | |
| 140 | |
| 141 | |
| 142 | |
| 143 | |
| 144 | |
| 145 | |
| 146 | |
| 147 | |
| 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"); |
| 153 | assert(ME.second->V && "Expected non-null"); |
| 154 | assert(ME.second->V.is<FileEntry *>() && "Expected FileEntry"); |
| 155 | } |
| 156 | |
| 157 | |
| 158 | |
| 159 | const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; } |
| 160 | |
| 161 | private: |
| 162 | friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>; |
| 163 | struct optional_none_tag {}; |
| 164 | |
| 165 | |
| 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 | |
| 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 | |
| 186 | static_assert(sizeof(FileEntryRef) == sizeof(const FileEntry *), |
| 187 | "FileEntryRef must avoid size overhead"); |
| 188 | |
| 189 | static_assert(std::is_trivially_copyable<FileEntryRef>::value, |
| 190 | "FileEntryRef must be trivially copyable"); |
| 191 | |
| 192 | } |
| 193 | |
| 194 | namespace llvm { |
| 195 | namespace optional_detail { |
| 196 | |
| 197 | |
| 198 | |
| 199 | template <> |
| 200 | class OptionalStorage<clang::FileEntryRef> |
| 201 | : public clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef> { |
| 202 | using StorageImpl = |
| 203 | clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef>; |
| 204 | |
| 205 | public: |
| 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 | |
| 218 | static_assert(sizeof(Optional<clang::FileEntryRef>) == |
| 219 | sizeof(clang::FileEntryRef), |
| 220 | "Optional<FileEntryRef> must avoid size overhead"); |
| 221 | |
| 222 | static_assert(std::is_trivially_copyable<Optional<clang::FileEntryRef>>::value, |
| 223 | "Optional<FileEntryRef> should be trivially copyable"); |
| 224 | |
| 225 | } |
| 226 | |
| 227 | |
| 228 | template <> 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 | |
| 243 | if (LHS.isSameRef(RHS)) |
| 244 | return true; |
| 245 | |
| 246 | |
| 247 | if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey()) |
| 248 | return false; |
| 249 | |
| 250 | |
| 251 | return LHS == RHS; |
| 252 | } |
| 253 | }; |
| 254 | |
| 255 | } |
| 256 | |
| 257 | namespace clang { |
| 258 | |
| 259 | |
| 260 | |
| 261 | |
| 262 | |
| 263 | |
| 264 | |
| 265 | |
| 266 | |
| 267 | |
| 268 | |
| 269 | |
| 270 | |
| 271 | |
| 272 | |
| 273 | |
| 274 | |
| 275 | |
| 276 | |
| 277 | |
| 278 | |
| 279 | |
| 280 | class OptionalFileEntryRefDegradesToFileEntryPtr |
| 281 | : public Optional<FileEntryRef> { |
| 282 | public: |
| 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 | |
| 314 | |
| 315 | |
| 316 | operator const FileEntry *() const { |
| 317 | return hasValue() ? &getValue().getFileEntry() : nullptr; |
| 318 | } |
| 319 | }; |
| 320 | |
| 321 | static_assert( |
| 322 | std::is_trivially_copyable< |
| 323 | OptionalFileEntryRefDegradesToFileEntryPtr>::value, |
| 324 | "OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable"); |
| 325 | |
| 326 | |
| 327 | |
| 328 | |
| 329 | |
| 330 | |
| 331 | class FileEntry { |
| 332 | friend class FileManager; |
| 333 | |
| 334 | std::string RealPathName; |
| 335 | off_t Size = 0; |
| 336 | time_t ModTime = 0; |
| 337 | const DirectoryEntry *Dir = nullptr; |
| 338 | llvm::sys::fs::UniqueID UniqueID; |
| 339 | unsigned UID = 0; |
| 340 | bool IsNamedPipe = false; |
| 341 | bool IsValid = false; |
| 342 | |
| 343 | |
| 344 | mutable std::unique_ptr<llvm::vfs::File> File; |
| 345 | |
| 346 | |
| 347 | std::unique_ptr<llvm::MemoryBuffer> Content; |
| 348 | |
| 349 | |
| 350 | |
| 351 | |
| 352 | |
| 353 | |
| 354 | |
| 355 | Optional<FileEntryRef> LastRef; |
| 356 | |
| 357 | public: |
| 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 | |
| 375 | const DirectoryEntry *getDir() const { return Dir; } |
| 376 | |
| 377 | bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; } |
| 378 | |
| 379 | |
| 380 | |
| 381 | bool isNamedPipe() const { return IsNamedPipe; } |
| 382 | |
| 383 | void closeFile() const; |
| 384 | }; |
| 385 | |
| 386 | bool FileEntryRef::isValid() const { return getFileEntry().isValid(); } |
| 387 | |
| 388 | off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); } |
| 389 | |
| 390 | unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); } |
| 391 | |
| 392 | const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const { |
| 393 | return getFileEntry().getUniqueID(); |
| 394 | } |
| 395 | |
| 396 | time_t FileEntryRef::getModificationTime() const { |
| 397 | return getFileEntry().getModificationTime(); |
| 398 | } |
| 399 | |
| 400 | bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); } |
| 401 | |
| 402 | void FileEntryRef::closeFile() const { getFileEntry().closeFile(); } |
| 32 | | Calling 'FileEntryRef::getFileEntry' | |
|
| 403 | |
| 404 | } |
| 405 | |
| 406 | #endif // LLVM_CLANG_BASIC_FILEENTRY_H |
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 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 | |
| 28 | namespace llvm { |
| 29 | |
| 30 | class raw_ostream; |
| 31 | |
| 32 | namespace optional_detail { |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | |
| 53 | template <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))> |
| 59 | class OptionalStorage { |
| 60 | union { |
| 61 | char empty; |
| 62 | T value; |
| 63 | }; |
| 64 | bool hasVal; |
| 65 | |
| 66 | public: |
| 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); |
| 97 | return value; |
| 98 | } |
| 99 | constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { |
| 100 | assert(hasVal); |
| 101 | return value; |
| 102 | } |
| 103 | #if LLVM_HAS_RVALUE_REFERENCE_THIS |
| 104 | T &&getValue() && noexcept { |
| 105 | assert(hasVal); |
| 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 | |
| 164 | template <typename T> class OptionalStorage<T, true> { |
| 165 | union { |
| 166 | char empty; |
| 167 | T value; |
| 168 | }; |
| 169 | bool hasVal = false; |
| 170 | |
| 171 | public: |
| 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); |
| 197 | return value; |
| 198 | } |
| 199 | constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { |
| 200 | assert(hasVal); |
| 201 | return value; |
| 202 | } |
| 203 | #if LLVM_HAS_RVALUE_REFERENCE_THIS |
| 204 | T &&getValue() && noexcept { |
| 205 | assert(hasVal); |
| 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 | } |
| 237 | |
| 238 | template <typename T> class Optional { |
| 239 | optional_detail::OptionalStorage<T> Storage; |
| 240 | |
| 241 | public: |
| 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 | |
| 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 | |
| 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_THIS |
| 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 | |
| 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 | |
| 328 | template <class T> llvm::hash_code hash_value(const Optional<T> &O) { |
| 329 | return O ? hash_combine(true, *O) : hash_value(false); |
| 330 | } |
| 331 | |
| 332 | template <typename T, typename U> |
| 333 | constexpr 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 | |
| 339 | template <typename T, typename U> |
| 340 | constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) { |
| 341 | return !(X == Y); |
| 342 | } |
| 343 | |
| 344 | template <typename T, typename U> |
| 345 | constexpr 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 | |
| 351 | template <typename T, typename U> |
| 352 | constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) { |
| 353 | return !(Y < X); |
| 354 | } |
| 355 | |
| 356 | template <typename T, typename U> |
| 357 | constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) { |
| 358 | return Y < X; |
| 359 | } |
| 360 | |
| 361 | template <typename T, typename U> |
| 362 | constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) { |
| 363 | return !(X < Y); |
| 364 | } |
| 365 | |
| 366 | template <typename T> |
| 367 | constexpr bool operator==(const Optional<T> &X, NoneType) { |
| 368 | return !X; |
| 369 | } |
| 370 | |
| 371 | template <typename T> |
| 372 | constexpr bool operator==(NoneType, const Optional<T> &X) { |
| 373 | return X == None; |
| 374 | } |
| 375 | |
| 376 | template <typename T> |
| 377 | constexpr bool operator!=(const Optional<T> &X, NoneType) { |
| 378 | return !(X == None); |
| 379 | } |
| 380 | |
| 381 | template <typename T> |
| 382 | constexpr bool operator!=(NoneType, const Optional<T> &X) { |
| 383 | return X != None; |
| 384 | } |
| 385 | |
| 386 | template <typename T> constexpr bool operator<(const Optional<T> &, NoneType) { |
| 387 | return false; |
| 388 | } |
| 389 | |
| 390 | template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) { |
| 391 | return X.hasValue(); |
| 392 | } |
| 393 | |
| 394 | template <typename T> |
| 395 | constexpr bool operator<=(const Optional<T> &X, NoneType) { |
| 396 | return !(None < X); |
| 397 | } |
| 398 | |
| 399 | template <typename T> |
| 400 | constexpr bool operator<=(NoneType, const Optional<T> &X) { |
| 401 | return !(X < None); |
| 402 | } |
| 403 | |
| 404 | template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) { |
| 405 | return None < X; |
| 406 | } |
| 407 | |
| 408 | template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) { |
| 409 | return X < None; |
| 410 | } |
| 411 | |
| 412 | template <typename T> |
| 413 | constexpr bool operator>=(const Optional<T> &X, NoneType) { |
| 414 | return None <= X; |
| 415 | } |
| 416 | |
| 417 | template <typename T> |
| 418 | constexpr bool operator>=(NoneType, const Optional<T> &X) { |
| 419 | return X <= None; |
| 420 | } |
| 421 | |
| 422 | template <typename T> |
| 423 | constexpr bool operator==(const Optional<T> &X, const T &Y) { |
| 424 | return X && *X == Y; |
| 425 | } |
| 426 | |
| 427 | template <typename T> |
| 428 | constexpr bool operator==(const T &X, const Optional<T> &Y) { |
| 429 | return Y && X == *Y; |
| 430 | } |
| 431 | |
| 432 | template <typename T> |
| 433 | constexpr bool operator!=(const Optional<T> &X, const T &Y) { |
| 434 | return !(X == Y); |
| 435 | } |
| 436 | |
| 437 | template <typename T> |
| 438 | constexpr bool operator!=(const T &X, const Optional<T> &Y) { |
| 439 | return !(X == Y); |
| 440 | } |
| 441 | |
| 442 | template <typename T> |
| 443 | constexpr bool operator<(const Optional<T> &X, const T &Y) { |
| 444 | return !X || *X < Y; |
| 445 | } |
| 446 | |
| 447 | template <typename T> |
| 448 | constexpr bool operator<(const T &X, const Optional<T> &Y) { |
| 449 | return Y && X < *Y; |
| 450 | } |
| 451 | |
| 452 | template <typename T> |
| 453 | constexpr bool operator<=(const Optional<T> &X, const T &Y) { |
| 454 | return !(Y < X); |
| 455 | } |
| 456 | |
| 457 | template <typename T> |
| 458 | constexpr bool operator<=(const T &X, const Optional<T> &Y) { |
| 459 | return !(Y < X); |
| 460 | } |
| 461 | |
| 462 | template <typename T> |
| 463 | constexpr bool operator>(const Optional<T> &X, const T &Y) { |
| 464 | return Y < X; |
| 465 | } |
| 466 | |
| 467 | template <typename T> |
| 468 | constexpr bool operator>(const T &X, const Optional<T> &Y) { |
| 469 | return Y < X; |
| 470 | } |
| 471 | |
| 472 | template <typename T> |
| 473 | constexpr bool operator>=(const Optional<T> &X, const T &Y) { |
| 474 | return !(X < Y); |
| 475 | } |
| 476 | |
| 477 | template <typename T> |
| 478 | constexpr bool operator>=(const T &X, const Optional<T> &Y) { |
| 479 | return !(X < Y); |
| 480 | } |
| 481 | |
| 482 | raw_ostream &operator<<(raw_ostream &OS, NoneType); |
| 483 | |
| 484 | template <typename T, typename = decltype(std::declval<raw_ostream &>() |
| 485 | << std::declval<const T &>())> |
| 486 | raw_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 | } |
| 495 | |
| 496 | #endif // LLVM_ADT_OPTIONAL_H |
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 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 | |
| 24 | namespace clang { |
| 25 | namespace FileMgr { |
| 26 | |
| 27 | template <class RefTy> class MapEntryOptionalStorage; |
| 28 | |
| 29 | } |
| 30 | |
| 31 | |
| 32 | |
| 33 | class DirectoryEntry { |
| 34 | friend class FileManager; |
| 35 | |
| 36 | |
| 37 | StringRef Name; |
| 38 | |
| 39 | public: |
| 40 | StringRef getName() const { return Name; } |
| 41 | }; |
| 42 | |
| 43 | |
| 44 | |
| 45 | class DirectoryEntryRef { |
| 46 | public: |
| 47 | const DirectoryEntry &getDirEntry() const { return *ME->getValue(); } |
| 48 | |
| 49 | StringRef getName() const { return ME->getKey(); } |
| 50 | |
| 51 | |
| 52 | |
| 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 | |
| 62 | bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; } |
| 63 | |
| 64 | DirectoryEntryRef() = delete; |
| 65 | DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {} |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | |
| 83 | |
| 84 | operator const DirectoryEntry *() const { return &getDirEntry(); } |
| 85 | |
| 86 | private: |
| 87 | friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>; |
| 88 | struct optional_none_tag {}; |
| 89 | |
| 90 | |
| 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 | |
| 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 | |
| 111 | namespace FileMgr { |
| 112 | |
| 113 | |
| 114 | |
| 115 | template <class RefTy> class MapEntryOptionalStorage { |
| 116 | using optional_none_tag = typename RefTy::optional_none_tag; |
| 117 | RefTy MaybeRef; |
| 118 | |
| 119 | public: |
| 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()); |
| 132 | return MaybeRef; |
| 133 | } |
| 134 | RefTy const &getValue() const LLVM_LVALUE_FUNCTION { |
| 135 | assert(hasValue()); |
| 136 | return MaybeRef; |
| 137 | } |
| 138 | #if LLVM_HAS_RVALUE_REFERENCE_THIS |
| 139 | RefTy &&getValue() && { |
| 140 | assert(hasValue()); |
| 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 | } |
| 156 | } |
| 157 | |
| 158 | namespace llvm { |
| 159 | namespace optional_detail { |
| 160 | |
| 161 | |
| 162 | |
| 163 | template <> |
| 164 | class OptionalStorage<clang::DirectoryEntryRef> |
| 165 | : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> { |
| 166 | using StorageImpl = |
| 167 | clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>; |
| 168 | |
| 169 | public: |
| 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 | |
| 182 | static_assert(sizeof(Optional<clang::DirectoryEntryRef>) == |
| 183 | sizeof(clang::DirectoryEntryRef), |
| 184 | "Optional<DirectoryEntryRef> must avoid size overhead"); |
| 185 | |
| 186 | static_assert( |
| 187 | std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value, |
| 188 | "Optional<DirectoryEntryRef> should be trivially copyable"); |
| 189 | |
| 190 | } |
| 191 | |
| 192 | |
| 193 | template <> 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 | |
| 211 | if (LHS.isSameRef(RHS)) |
| 212 | return true; |
| 213 | |
| 214 | |
| 215 | if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey()) |
| 216 | return false; |
| 217 | |
| 218 | |
| 219 | return LHS == RHS; |
| 220 | } |
| 221 | }; |
| 222 | |
| 223 | } |
| 224 | |
| 225 | namespace clang { |
| 226 | |
| 227 | |
| 228 | |
| 229 | |
| 230 | |
| 231 | |
| 232 | |
| 233 | |
| 234 | |
| 235 | |
| 236 | |
| 237 | |
| 238 | |
| 239 | |
| 240 | |
| 241 | |
| 242 | |
| 243 | |
| 244 | |
| 245 | |
| 246 | |
| 247 | |
| 248 | |
| 249 | class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr |
| 250 | : public Optional<DirectoryEntryRef> { |
| 251 | public: |
| 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 | |
| 283 | |
| 284 | |
| 285 | operator const DirectoryEntry *() const { |
| 286 | return hasValue() ? &getValue().getDirEntry() : nullptr; |
| 287 | } |
| 288 | }; |
| 289 | |
| 290 | static_assert(std::is_trivially_copyable< |
| 291 | OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value, |
| 292 | "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be " |
| 293 | "trivially copyable"); |
| 294 | |
| 295 | } |
| 296 | |
| 297 | #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H |