Bug Summary

File:llvm/include/llvm/ADT/FunctionExtras.h
Warning:line 186, column 5
Undefined or garbage value returned to caller

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name LazyReexports.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 -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/build-llvm/lib/ExecutionEngine/Orc -resource-dir /usr/lib/llvm-13/lib/clang/13.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/build-llvm/lib/ExecutionEngine/Orc -I /build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc -I /build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/build-llvm/include -I /build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../x86_64-linux-gnu/include -internal-isystem /usr/lib/llvm-13/lib/clang/13.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/build-llvm/lib/ExecutionEngine/Orc -fdebug-prefix-map=/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-04-05-202135-9119-1 -x c++ /build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp

/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp

1//===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ExecutionEngine/Orc/LazyReexports.h"
10
11#include "llvm/ADT/Triple.h"
12#include "llvm/ExecutionEngine/Orc/OrcABISupport.h"
13
14#define DEBUG_TYPE"orc" "orc"
15
16namespace llvm {
17namespace orc {
18
19LazyCallThroughManager::LazyCallThroughManager(
20 ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP)
21 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
22
23Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
24 JITDylib &SourceJD, SymbolStringPtr SymbolName,
25 NotifyResolvedFunction NotifyResolved) {
26 assert(TP && "TrampolinePool not set")((TP && "TrampolinePool not set") ? static_cast<void
> (0) : __assert_fail ("TP && \"TrampolinePool not set\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 26, __PRETTY_FUNCTION__))
;
27
28 std::lock_guard<std::mutex> Lock(LCTMMutex);
29 auto Trampoline = TP->getTrampoline();
30
31 if (!Trampoline)
32 return Trampoline.takeError();
33
34 Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
35 Notifiers[*Trampoline] = std::move(NotifyResolved);
36 return *Trampoline;
37}
38
39JITTargetAddress LazyCallThroughManager::reportCallThroughError(Error Err) {
40 ES.reportError(std::move(Err));
41 return ErrorHandlerAddr;
42}
43
44Expected<LazyCallThroughManager::ReexportsEntry>
45LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
46 std::lock_guard<std::mutex> Lock(LCTMMutex);
47 auto I = Reexports.find(TrampolineAddr);
48 if (I == Reexports.end())
49 return createStringError(inconvertibleErrorCode(),
50 "Missing reexport for trampoline address %p",
51 TrampolineAddr);
52 return I->second;
53}
54
55Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
56 JITTargetAddress ResolvedAddr) {
57 NotifyResolvedFunction NotifyResolved;
7
Calling defaulted default constructor for 'unique_function<llvm::Error (unsigned long)>'
12
Returning from default constructor for 'unique_function<llvm::Error (unsigned long)>'
58 {
59 std::lock_guard<std::mutex> Lock(LCTMMutex);
60 auto I = Notifiers.find(TrampolineAddr);
61 if (I != Notifiers.end()) {
13
Assuming the condition is true
14
Taking true branch
62 NotifyResolved = std::move(I->second);
15
Calling defaulted move assignment operator for 'unique_function<llvm::Error (unsigned long)>'
25
Returning from move assignment operator for 'unique_function<llvm::Error (unsigned long)>'
63 Notifiers.erase(I);
64 }
65 }
66
67 return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
26
'?' condition is true
27
Calling 'unique_function::operator()'
68}
69
70void LazyCallThroughManager::resolveTrampolineLandingAddress(
71 JITTargetAddress TrampolineAddr,
72 NotifyLandingResolvedFunction NotifyLandingResolved) {
73
74 auto Entry = findReexport(TrampolineAddr);
75 if (!Entry)
76 return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
77
78 // Declaring SLS and the callback outside of the call to ES.lookup is a
79 // workaround to fix build failures on AIX and on z/OS platforms.
80 SymbolLookupSet SLS({Entry->SymbolName});
81 auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
82 NotifyLandingResolved = std::move(NotifyLandingResolved)](
83 Expected<SymbolMap> Result) mutable {
84 if (Result) {
1
Taking true branch
85 assert(Result->size() == 1 && "Unexpected result size")((Result->size() == 1 && "Unexpected result size")
? static_cast<void> (0) : __assert_fail ("Result->size() == 1 && \"Unexpected result size\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 85, __PRETTY_FUNCTION__))
;
2
Assuming the condition is true
3
'?' condition is true
86 assert(Result->count(SymbolName) && "Unexpected result value")((Result->count(SymbolName) && "Unexpected result value"
) ? static_cast<void> (0) : __assert_fail ("Result->count(SymbolName) && \"Unexpected result value\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 86, __PRETTY_FUNCTION__))
;
4
Assuming the condition is true
5
'?' condition is true
87 JITTargetAddress LandingAddr = (*Result)[SymbolName].getAddress();
88
89 if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
6
Calling 'LazyCallThroughManager::notifyResolved'
90 NotifyLandingResolved(reportCallThroughError(std::move(Err)));
91 else
92 NotifyLandingResolved(LandingAddr);
93 } else {
94 NotifyLandingResolved(reportCallThroughError(Result.takeError()));
95 }
96 };
97
98 ES.lookup(LookupKind::Static,
99 makeJITDylibSearchOrder(Entry->SourceJD,
100 JITDylibLookupFlags::MatchAllSymbols),
101 std::move(SLS), SymbolState::Ready, std::move(Callback),
102 NoDependenciesToRegister);
103}
104
105Expected<std::unique_ptr<LazyCallThroughManager>>
106createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
107 JITTargetAddress ErrorHandlerAddr) {
108 switch (T.getArch()) {
109 default:
110 return make_error<StringError>(
111 std::string("No callback manager available for ") + T.str(),
112 inconvertibleErrorCode());
113
114 case Triple::aarch64:
115 case Triple::aarch64_32:
116 return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
117 ErrorHandlerAddr);
118
119 case Triple::x86:
120 return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
121
122 case Triple::mips:
123 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
124 ErrorHandlerAddr);
125
126 case Triple::mipsel:
127 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
128 ErrorHandlerAddr);
129
130 case Triple::mips64:
131 case Triple::mips64el:
132 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
133
134 case Triple::x86_64:
135 if (T.getOS() == Triple::OSType::Win32)
136 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
137 ES, ErrorHandlerAddr);
138 else
139 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
140 ES, ErrorHandlerAddr);
141 }
142}
143
144LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
145 LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
146 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc)
147 : MaterializationUnit(extractFlags(CallableAliases), nullptr),
148 LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
149 CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
150
151StringRef LazyReexportsMaterializationUnit::getName() const {
152 return "<Lazy Reexports>";
153}
154
155void LazyReexportsMaterializationUnit::materialize(
156 std::unique_ptr<MaterializationResponsibility> R) {
157 auto RequestedSymbols = R->getRequestedSymbols();
158
159 SymbolAliasMap RequestedAliases;
160 for (auto &RequestedSymbol : RequestedSymbols) {
161 auto I = CallableAliases.find(RequestedSymbol);
162 assert(I != CallableAliases.end() && "Symbol not found in alias map?")((I != CallableAliases.end() && "Symbol not found in alias map?"
) ? static_cast<void> (0) : __assert_fail ("I != CallableAliases.end() && \"Symbol not found in alias map?\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 162, __PRETTY_FUNCTION__))
;
163 RequestedAliases[I->first] = std::move(I->second);
164 CallableAliases.erase(I);
165 }
166
167 if (!CallableAliases.empty())
168 if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
169 std::move(CallableAliases),
170 AliaseeTable))) {
171 R->getExecutionSession().reportError(std::move(Err));
172 R->failMaterialization();
173 return;
174 }
175
176 IndirectStubsManager::StubInitsMap StubInits;
177 for (auto &Alias : RequestedAliases) {
178
179 auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
180 SourceJD, Alias.second.Aliasee,
181 [&ISManager = this->ISManager,
182 StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
183 return ISManager.updatePointer(*StubSym, ResolvedAddr);
184 });
185
186 if (!CallThroughTrampoline) {
187 SourceJD.getExecutionSession().reportError(
188 CallThroughTrampoline.takeError());
189 R->failMaterialization();
190 return;
191 }
192
193 StubInits[*Alias.first] =
194 std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
195 }
196
197 if (AliaseeTable != nullptr && !RequestedAliases.empty())
198 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
199
200 if (auto Err = ISManager.createStubs(StubInits)) {
201 SourceJD.getExecutionSession().reportError(std::move(Err));
202 R->failMaterialization();
203 return;
204 }
205
206 SymbolMap Stubs;
207 for (auto &Alias : RequestedAliases)
208 Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
209
210 // No registered dependencies, so these calls cannot fail.
211 cantFail(R->notifyResolved(Stubs));
212 cantFail(R->notifyEmitted());
213}
214
215void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
216 const SymbolStringPtr &Name) {
217 assert(CallableAliases.count(Name) &&((CallableAliases.count(Name) && "Symbol not covered by this MaterializationUnit"
) ? static_cast<void> (0) : __assert_fail ("CallableAliases.count(Name) && \"Symbol not covered by this MaterializationUnit\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 218, __PRETTY_FUNCTION__))
218 "Symbol not covered by this MaterializationUnit")((CallableAliases.count(Name) && "Symbol not covered by this MaterializationUnit"
) ? static_cast<void> (0) : __assert_fail ("CallableAliases.count(Name) && \"Symbol not covered by this MaterializationUnit\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 218, __PRETTY_FUNCTION__))
;
219 CallableAliases.erase(Name);
220}
221
222SymbolFlagsMap
223LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
224 SymbolFlagsMap SymbolFlags;
225 for (auto &KV : Aliases) {
226 assert(KV.second.AliasFlags.isCallable() &&((KV.second.AliasFlags.isCallable() && "Lazy re-exports must be callable symbols"
) ? static_cast<void> (0) : __assert_fail ("KV.second.AliasFlags.isCallable() && \"Lazy re-exports must be callable symbols\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 227, __PRETTY_FUNCTION__))
227 "Lazy re-exports must be callable symbols")((KV.second.AliasFlags.isCallable() && "Lazy re-exports must be callable symbols"
) ? static_cast<void> (0) : __assert_fail ("KV.second.AliasFlags.isCallable() && \"Lazy re-exports must be callable symbols\""
, "/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 227, __PRETTY_FUNCTION__))
;
228 SymbolFlags[KV.first] = KV.second.AliasFlags;
229 }
230 return SymbolFlags;
231}
232
233} // End namespace orc.
234} // End namespace llvm.

/build/llvm-toolchain-snapshot-13~++20210405022414+5f57793c4fe4/llvm/include/llvm/ADT/FunctionExtras.h

1//===- FunctionExtras.h - Function type erasure utilities -------*- 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/// \file
9/// This file provides a collection of function (or more generally, callable)
10/// type erasure utilities supplementing those provided by the standard library
11/// in `<function>`.
12///
13/// It provides `unique_function`, which works like `std::function` but supports
14/// move-only callable objects and const-qualification.
15///
16/// Future plans:
17/// - Add a `function` that provides ref-qualified support, which doesn't work
18/// with `std::function`.
19/// - Provide support for specifying multiple signatures to type erase callable
20/// objects with an overload set, such as those produced by generic lambdas.
21/// - Expand to include a copyable utility that directly replaces std::function
22/// but brings the above improvements.
23///
24/// Note that LLVM's utilities are greatly simplified by not supporting
25/// allocators.
26///
27/// If the standard library ever begins to provide comparable facilities we can
28/// consider switching to those.
29///
30//===----------------------------------------------------------------------===//
31
32#ifndef LLVM_ADT_FUNCTIONEXTRAS_H
33#define LLVM_ADT_FUNCTIONEXTRAS_H
34
35#include "llvm/ADT/PointerIntPair.h"
36#include "llvm/ADT/PointerUnion.h"
37#include "llvm/Support/MemAlloc.h"
38#include "llvm/Support/type_traits.h"
39#include <memory>
40#include <type_traits>
41
42namespace llvm {
43
44/// unique_function is a type-erasing functor similar to std::function.
45///
46/// It can hold move-only function objects, like lambdas capturing unique_ptrs.
47/// Accordingly, it is movable but not copyable.
48///
49/// It supports const-qualification:
50/// - unique_function<int() const> has a const operator().
51/// It can only hold functions which themselves have a const operator().
52/// - unique_function<int()> has a non-const operator().
53/// It can hold functions with a non-const operator(), like mutable lambdas.
54template <typename FunctionT> class unique_function;
55
56namespace detail {
57
58template <typename T>
59using EnableIfTrivial =
60 std::enable_if_t<llvm::is_trivially_move_constructible<T>::value &&
61 std::is_trivially_destructible<T>::value>;
62template <typename CallableT, typename ThisT>
63using EnableUnlessSameType = std::enable_if_t<!std::is_same<
64 std::remove_cv_t<std::remove_reference_t<CallableT>>, ThisT>::value>;
65template <typename CallableT, typename Ret, typename... Params>
66using EnableIfCallable =
67 std::enable_if_t<std::is_void<Ret>::value ||
68 std::is_convertible<decltype(std::declval<CallableT>()(
69 std::declval<Params>()...)),
70 Ret>::value>;
71
72template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
73protected:
74 static constexpr size_t InlineStorageSize = sizeof(void *) * 3;
75
76 template <typename T, class = void>
77 struct IsSizeLessThanThresholdT : std::false_type {};
78
79 template <typename T>
80 struct IsSizeLessThanThresholdT<
81 T, std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
82
83 // Provide a type function to map parameters that won't observe extra copies
84 // or moves and which are small enough to likely pass in register to values
85 // and all other types to l-value reference types. We use this to compute the
86 // types used in our erased call utility to minimize copies and moves unless
87 // doing so would force things unnecessarily into memory.
88 //
89 // The heuristic used is related to common ABI register passing conventions.
90 // It doesn't have to be exact though, and in one way it is more strict
91 // because we want to still be able to observe either moves *or* copies.
92 template <typename T>
93 using AdjustedParamT = typename std::conditional<
94 !std::is_reference<T>::value &&
95 llvm::is_trivially_copy_constructible<T>::value &&
96 llvm::is_trivially_move_constructible<T>::value &&
97 IsSizeLessThanThresholdT<T>::value,
98 T, T &>::type;
99
100 // The type of the erased function pointer we use as a callback to dispatch to
101 // the stored callable when it is trivial to move and destroy.
102 using CallPtrT = ReturnT (*)(void *CallableAddr,
103 AdjustedParamT<ParamTs>... Params);
104 using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
105 using DestroyPtrT = void (*)(void *CallableAddr);
106
107 /// A struct to hold a single trivial callback with sufficient alignment for
108 /// our bitpacking.
109 struct alignas(8) TrivialCallback {
110 CallPtrT CallPtr;
111 };
112
113 /// A struct we use to aggregate three callbacks when we need full set of
114 /// operations.
115 struct alignas(8) NonTrivialCallbacks {
116 CallPtrT CallPtr;
117 MovePtrT MovePtr;
118 DestroyPtrT DestroyPtr;
119 };
120
121 // Create a pointer union between either a pointer to a static trivial call
122 // pointer in a struct or a pointer to a static struct of the call, move, and
123 // destroy pointers.
124 using CallbackPointerUnionT =
125 PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
126
127 // The main storage buffer. This will either have a pointer to out-of-line
128 // storage or an inline buffer storing the callable.
129 union StorageUnionT {
130 // For out-of-line storage we keep a pointer to the underlying storage and
131 // the size. This is enough to deallocate the memory.
132 struct OutOfLineStorageT {
133 void *StoragePtr;
134 size_t Size;
135 size_t Alignment;
136 } OutOfLineStorage;
137 static_assert(
138 sizeof(OutOfLineStorageT) <= InlineStorageSize,
139 "Should always use all of the out-of-line storage for inline storage!");
140
141 // For in-line storage, we just provide an aligned character buffer. We
142 // provide three pointers worth of storage here.
143 // This is mutable as an inlined `const unique_function<void() const>` may
144 // still modify its own mutable members.
145 mutable
146 typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
147 InlineStorage;
148 } StorageUnion;
149
150 // A compressed pointer to either our dispatching callback or our table of
151 // dispatching callbacks and the flag for whether the callable itself is
152 // stored inline or not.
153 PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
154
155 bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
156
157 bool isTrivialCallback() const {
158 return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
159 }
160
161 CallPtrT getTrivialCallback() const {
162 return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
163 }
164
165 NonTrivialCallbacks *getNonTrivialCallbacks() const {
166 return CallbackAndInlineFlag.getPointer()
167 .template get<NonTrivialCallbacks *>();
168 }
169
170 CallPtrT getCallPtr() const {
171 return isTrivialCallback() ? getTrivialCallback()
172 : getNonTrivialCallbacks()->CallPtr;
173 }
174
175 // These three functions are only const in the narrow sense. They return
176 // mutable pointers to function state.
177 // This allows unique_function<T const>::operator() to be const, even if the
178 // underlying functor may be internally mutable.
179 //
180 // const callers must ensure they're only used in const-correct ways.
181 void *getCalleePtr() const {
182 return isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
29
Assuming the condition is false
30
'?' condition is false
31
Calling 'UniqueFunctionBase::getOutOfLineStorage'
183 }
184 void *getInlineStorage() const { return &StorageUnion.InlineStorage; }
185 void *getOutOfLineStorage() const {
186 return StorageUnion.OutOfLineStorage.StoragePtr;
32
Undefined or garbage value returned to caller
187 }
188
189 size_t getOutOfLineStorageSize() const {
190 return StorageUnion.OutOfLineStorage.Size;
191 }
192 size_t getOutOfLineStorageAlignment() const {
193 return StorageUnion.OutOfLineStorage.Alignment;
194 }
195
196 void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
197 StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
198 }
199
200 template <typename CalledAsT>
201 static ReturnT CallImpl(void *CallableAddr,
202 AdjustedParamT<ParamTs>... Params) {
203 auto &Func = *reinterpret_cast<CalledAsT *>(CallableAddr);
204 return Func(std::forward<ParamTs>(Params)...);
205 }
206
207 template <typename CallableT>
208 static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
209 new (LHSCallableAddr)
210 CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
211 }
212
213 template <typename CallableT>
214 static void DestroyImpl(void *CallableAddr) noexcept {
215 reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
216 }
217
218 // The pointers to call/move/destroy functions are determined for each
219 // callable type (and called-as type, which determines the overload chosen).
220 // (definitions are out-of-line).
221
222 // By default, we need an object that contains all the different
223 // type erased behaviors needed. Create a static instance of the struct type
224 // here and each instance will contain a pointer to it.
225 // Wrap in a struct to avoid https://gcc.gnu.org/PR71954
226 template <typename CallableT, typename CalledAs, typename Enable = void>
227 struct CallbacksHolder {
228 static NonTrivialCallbacks Callbacks;
229 };
230 // See if we can create a trivial callback. We need the callable to be
231 // trivially moved and trivially destroyed so that we don't have to store
232 // type erased callbacks for those operations.
233 template <typename CallableT, typename CalledAs>
234 struct CallbacksHolder<CallableT, CalledAs, EnableIfTrivial<CallableT>> {
235 static TrivialCallback Callbacks;
236 };
237
238 // A simple tag type so the call-as type to be passed to the constructor.
239 template <typename T> struct CalledAs {};
240
241 // Essentially the "main" unique_function constructor, but subclasses
242 // provide the qualified type to be used for the call.
243 // (We always store a T, even if the call will use a pointer to const T).
244 template <typename CallableT, typename CalledAsT>
245 UniqueFunctionBase(CallableT Callable, CalledAs<CalledAsT>) {
246 bool IsInlineStorage = true;
247 void *CallableAddr = getInlineStorage();
248 if (sizeof(CallableT) > InlineStorageSize ||
249 alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
250 IsInlineStorage = false;
251 // Allocate out-of-line storage. FIXME: Use an explicit alignment
252 // parameter in C++17 mode.
253 auto Size = sizeof(CallableT);
254 auto Alignment = alignof(CallableT);
255 CallableAddr = allocate_buffer(Size, Alignment);
256 setOutOfLineStorage(CallableAddr, Size, Alignment);
257 }
258
259 // Now move into the storage.
260 new (CallableAddr) CallableT(std::move(Callable));
261 CallbackAndInlineFlag.setPointerAndInt(
262 &CallbacksHolder<CallableT, CalledAsT>::Callbacks, IsInlineStorage);
263 }
264
265 ~UniqueFunctionBase() {
266 if (!CallbackAndInlineFlag.getPointer())
267 return;
268
269 // Cache this value so we don't re-check it after type-erased operations.
270 bool IsInlineStorage = isInlineStorage();
271
272 if (!isTrivialCallback())
273 getNonTrivialCallbacks()->DestroyPtr(
274 IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
275
276 if (!IsInlineStorage)
277 deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
278 getOutOfLineStorageAlignment());
279 }
280
281 UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
282 // Copy the callback and inline flag.
283 CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
284
285 // If the RHS is empty, just copying the above is sufficient.
286 if (!RHS)
21
Taking true branch
287 return;
22
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
288
289 if (!isInlineStorage()) {
290 // The out-of-line case is easiest to move.
291 StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
292 } else if (isTrivialCallback()) {
293 // Move is trivial, just memcpy the bytes across.
294 memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
295 } else {
296 // Non-trivial move, so dispatch to a type-erased implementation.
297 getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
298 RHS.getInlineStorage());
299 }
300
301 // Clear the old callback and inline flag to get back to as-if-null.
302 RHS.CallbackAndInlineFlag = {};
303
304#ifndef NDEBUG
305 // In debug builds, we also scribble across the rest of the storage.
306 memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
307#endif
308 }
309
310 UniqueFunctionBase &operator=(UniqueFunctionBase &&RHS) noexcept {
311 if (this == &RHS)
17
Taking false branch
312 return *this;
313
314 // Because we don't try to provide any exception safety guarantees we can
315 // implement move assignment very simply by first destroying the current
316 // object and then move-constructing over top of it.
317 this->~UniqueFunctionBase();
318 new (this) UniqueFunctionBase(std::move(RHS));
18
Calling 'operator new'
19
Returning from 'operator new'
20
Calling move constructor for 'UniqueFunctionBase<llvm::Error, unsigned long>'
23
Returning from move constructor for 'UniqueFunctionBase<llvm::Error, unsigned long>'
319 return *this;
320 }
321
322 UniqueFunctionBase() = default;
9
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
323
324public:
325 explicit operator bool() const {
326 return (bool)CallbackAndInlineFlag.getPointer();
327 }
328};
329
330template <typename R, typename... P>
331template <typename CallableT, typename CalledAsT, typename Enable>
332typename UniqueFunctionBase<R, P...>::NonTrivialCallbacks UniqueFunctionBase<
333 R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
334 &CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
335
336template <typename R, typename... P>
337template <typename CallableT, typename CalledAsT>
338typename UniqueFunctionBase<R, P...>::TrivialCallback
339 UniqueFunctionBase<R, P...>::CallbacksHolder<
340 CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
341 &CallImpl<CalledAsT>};
342
343} // namespace detail
344
345template <typename R, typename... P>
346class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
347 using Base = detail::UniqueFunctionBase<R, P...>;
348
349public:
350 unique_function() = default;
8
Calling defaulted default constructor for 'UniqueFunctionBase<llvm::Error, unsigned long>'
10
Returning from default constructor for 'UniqueFunctionBase<llvm::Error, unsigned long>'
11
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
351 unique_function(std::nullptr_t) {}
352 unique_function(unique_function &&) = default;
353 unique_function(const unique_function &) = delete;
354 unique_function &operator=(unique_function &&) = default;
16
Calling move assignment operator for 'UniqueFunctionBase<llvm::Error, unsigned long>'
24
Returning from move assignment operator for 'UniqueFunctionBase<llvm::Error, unsigned long>'
355 unique_function &operator=(const unique_function &) = delete;
356
357 template <typename CallableT>
358 unique_function(
359 CallableT Callable,
360 detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
361 detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
362 : Base(std::forward<CallableT>(Callable),
363 typename Base::template CalledAs<CallableT>{}) {}
364
365 R operator()(P... Params) {
366 return this->getCallPtr()(this->getCalleePtr(), Params...);
28
Calling 'UniqueFunctionBase::getCalleePtr'
367 }
368};
369
370template <typename R, typename... P>
371class unique_function<R(P...) const>
372 : public detail::UniqueFunctionBase<R, P...> {
373 using Base = detail::UniqueFunctionBase<R, P...>;
374
375public:
376 unique_function() = default;
377 unique_function(std::nullptr_t) {}
378 unique_function(unique_function &&) = default;
379 unique_function(const unique_function &) = delete;
380 unique_function &operator=(unique_function &&) = default;
381 unique_function &operator=(const unique_function &) = delete;
382
383 template <typename CallableT>
384 unique_function(
385 CallableT Callable,
386 detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
387 detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
388 : Base(std::forward<CallableT>(Callable),
389 typename Base::template CalledAs<const CallableT>{}) {}
390
391 R operator()(P... Params) const {
392 return this->getCallPtr()(this->getCalleePtr(), Params...);
393 }
394};
395
396} // end namespace llvm
397
398#endif // LLVM_ADT_FUNCTIONEXTRAS_H