Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -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 -mthread-model posix -mframe-pointer=none -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-11/lib/clang/11.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/build-llvm/lib/ExecutionEngine/Orc -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/build-llvm/include -I /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/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/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/llvm-11/lib/clang/11.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-11~++20200309111110+2c36c23f347/build-llvm/lib/ExecutionEngine/Orc -fdebug-prefix-map=/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347=. -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -o /tmp/scan-build-2020-03-09-184146-41876-1 -x c++ /build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp

/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/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,
21 std::unique_ptr<TrampolinePool> TP)
22 : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(std::move(TP)) {}
23
24Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
25 JITDylib &SourceJD, SymbolStringPtr SymbolName,
26 NotifyResolvedFunction NotifyResolved) {
27 std::lock_guard<std::mutex> Lock(LCTMMutex);
28 auto Trampoline = TP->getTrampoline();
29
30 if (!Trampoline)
31 return Trampoline.takeError();
32
33 Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
34 Notifiers[*Trampoline] = std::move(NotifyResolved);
35 return *Trampoline;
36}
37
38Expected<LazyCallThroughManager::ReexportsEntry>
39LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
40 std::lock_guard<std::mutex> Lock(LCTMMutex);
41 auto I = Reexports.find(TrampolineAddr);
42 if (I == Reexports.end())
43 return createStringError(inconvertibleErrorCode(),
44 "Missing reexport for trampoline address %p",
45 TrampolineAddr);
46 return I->second;
47}
48
49Expected<JITTargetAddress>
50LazyCallThroughManager::resolveSymbol(const ReexportsEntry &RE) {
51 auto LookupResult =
52 ES.lookup(makeJITDylibSearchOrder(RE.SourceJD,
53 JITDylibLookupFlags::MatchAllSymbols),
54 RE.SymbolName, SymbolState::Ready);
55
56 if (!LookupResult)
57 return LookupResult.takeError();
58
59 return LookupResult->getAddress();
60}
61
62Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
63 JITTargetAddress ResolvedAddr) {
64 NotifyResolvedFunction NotifyResolved;
1
Calling defaulted default constructor for 'unique_function<llvm::Error (unsigned long)>'
3
Returning from default constructor for 'unique_function<llvm::Error (unsigned long)>'
65 {
66 std::lock_guard<std::mutex> Lock(LCTMMutex);
67 auto I = Notifiers.find(TrampolineAddr);
68 if (I != Notifiers.end()) {
4
Assuming the condition is true
5
Taking true branch
69 NotifyResolved = std::move(I->second);
6
Calling move assignment operator for 'unique_function<llvm::Error (unsigned long)>'
14
Returning from move assignment operator for 'unique_function<llvm::Error (unsigned long)>'
70 Notifiers.erase(I);
71 }
72 }
73
74 return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
15
'?' condition is true
16
Calling 'unique_function::operator()'
75}
76
77Expected<std::unique_ptr<LazyCallThroughManager>>
78createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES,
79 JITTargetAddress ErrorHandlerAddr) {
80 switch (T.getArch()) {
81 default:
82 return make_error<StringError>(
83 std::string("No callback manager available for ") + T.str(),
84 inconvertibleErrorCode());
85
86 case Triple::aarch64:
87 case Triple::aarch64_32:
88 return LocalLazyCallThroughManager::Create<OrcAArch64>(ES,
89 ErrorHandlerAddr);
90
91 case Triple::x86:
92 return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr);
93
94 case Triple::mips:
95 return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES,
96 ErrorHandlerAddr);
97
98 case Triple::mipsel:
99 return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES,
100 ErrorHandlerAddr);
101
102 case Triple::mips64:
103 case Triple::mips64el:
104 return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr);
105
106 case Triple::x86_64:
107 if (T.getOS() == Triple::OSType::Win32)
108 return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>(
109 ES, ErrorHandlerAddr);
110 else
111 return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>(
112 ES, ErrorHandlerAddr);
113 }
114}
115
116LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
117 LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
118 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc,
119 VModuleKey K)
120 : MaterializationUnit(extractFlags(CallableAliases), nullptr, std::move(K)),
121 LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
122 CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
123
124StringRef LazyReexportsMaterializationUnit::getName() const {
125 return "<Lazy Reexports>";
126}
127
128void LazyReexportsMaterializationUnit::materialize(
129 MaterializationResponsibility R) {
130 auto RequestedSymbols = R.getRequestedSymbols();
131
132 SymbolAliasMap RequestedAliases;
133 for (auto &RequestedSymbol : RequestedSymbols) {
134 auto I = CallableAliases.find(RequestedSymbol);
135 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-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 135, __PRETTY_FUNCTION__))
;
136 RequestedAliases[I->first] = std::move(I->second);
137 CallableAliases.erase(I);
138 }
139
140 if (!CallableAliases.empty())
141 R.replace(lazyReexports(LCTManager, ISManager, SourceJD,
142 std::move(CallableAliases), AliaseeTable));
143
144 IndirectStubsManager::StubInitsMap StubInits;
145 for (auto &Alias : RequestedAliases) {
146
147 auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
148 SourceJD, Alias.second.Aliasee,
149 [&ISManager = this->ISManager,
150 StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
151 return ISManager.updatePointer(*StubSym, ResolvedAddr);
152 });
153
154 if (!CallThroughTrampoline) {
155 SourceJD.getExecutionSession().reportError(
156 CallThroughTrampoline.takeError());
157 R.failMaterialization();
158 return;
159 }
160
161 StubInits[*Alias.first] =
162 std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
163 }
164
165 if (AliaseeTable != nullptr && !RequestedAliases.empty())
166 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
167
168 if (auto Err = ISManager.createStubs(StubInits)) {
169 SourceJD.getExecutionSession().reportError(std::move(Err));
170 R.failMaterialization();
171 return;
172 }
173
174 SymbolMap Stubs;
175 for (auto &Alias : RequestedAliases)
176 Stubs[Alias.first] = ISManager.findStub(*Alias.first, false);
177
178 // No registered dependencies, so these calls cannot fail.
179 cantFail(R.notifyResolved(Stubs));
180 cantFail(R.notifyEmitted());
181}
182
183void LazyReexportsMaterializationUnit::discard(const JITDylib &JD,
184 const SymbolStringPtr &Name) {
185 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-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 186, __PRETTY_FUNCTION__))
186 "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-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 186, __PRETTY_FUNCTION__))
;
187 CallableAliases.erase(Name);
188}
189
190SymbolFlagsMap
191LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) {
192 SymbolFlagsMap SymbolFlags;
193 for (auto &KV : Aliases) {
194 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-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 195, __PRETTY_FUNCTION__))
195 "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-11~++20200309111110+2c36c23f347/llvm/lib/ExecutionEngine/Orc/LazyReexports.cpp"
, 195, __PRETTY_FUNCTION__))
;
196 SymbolFlags[KV.first] = KV.second.AliasFlags;
197 }
198 return SymbolFlags;
199}
200
201} // End namespace orc.
202} // End namespace llvm.

/build/llvm-toolchain-snapshot-11~++20200309111110+2c36c23f347/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.
15///
16/// Future plans:
17/// - Add a `function` that provides const, volatile, and ref-qualified support,
18/// which doesn't work 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_FUNCTION_EXTRAS_H
33#define LLVM_ADT_FUNCTION_EXTRAS_H
34
35#include "llvm/ADT/PointerIntPair.h"
36#include "llvm/ADT/PointerUnion.h"
37#include "llvm/Support/type_traits.h"
38#include <memory>
39
40namespace llvm {
41
42template <typename FunctionT> class unique_function;
43
44template <typename ReturnT, typename... ParamTs>
45class unique_function<ReturnT(ParamTs...)> {
46 static constexpr size_t InlineStorageSize = sizeof(void *) * 3;
47
48 // MSVC has a bug and ICEs if we give it a particular dependent value
49 // expression as part of the `std::conditional` below. To work around this,
50 // we build that into a template struct's constexpr bool.
51 template <typename T> struct IsSizeLessThanThresholdT {
52 static constexpr bool value = sizeof(T) <= (2 * sizeof(void *));
53 };
54
55 // Provide a type function to map parameters that won't observe extra copies
56 // or moves and which are small enough to likely pass in register to values
57 // and all other types to l-value reference types. We use this to compute the
58 // types used in our erased call utility to minimize copies and moves unless
59 // doing so would force things unnecessarily into memory.
60 //
61 // The heuristic used is related to common ABI register passing conventions.
62 // It doesn't have to be exact though, and in one way it is more strict
63 // because we want to still be able to observe either moves *or* copies.
64 template <typename T>
65 using AdjustedParamT = typename std::conditional<
66 !std::is_reference<T>::value &&
67 llvm::is_trivially_copy_constructible<T>::value &&
68 llvm::is_trivially_move_constructible<T>::value &&
69 IsSizeLessThanThresholdT<T>::value,
70 T, T &>::type;
71
72 // The type of the erased function pointer we use as a callback to dispatch to
73 // the stored callable when it is trivial to move and destroy.
74 using CallPtrT = ReturnT (*)(void *CallableAddr,
75 AdjustedParamT<ParamTs>... Params);
76 using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
77 using DestroyPtrT = void (*)(void *CallableAddr);
78
79 /// A struct to hold a single trivial callback with sufficient alignment for
80 /// our bitpacking.
81 struct alignas(8) TrivialCallback {
82 CallPtrT CallPtr;
83 };
84
85 /// A struct we use to aggregate three callbacks when we need full set of
86 /// operations.
87 struct alignas(8) NonTrivialCallbacks {
88 CallPtrT CallPtr;
89 MovePtrT MovePtr;
90 DestroyPtrT DestroyPtr;
91 };
92
93 // Create a pointer union between either a pointer to a static trivial call
94 // pointer in a struct or a pointer to a static struct of the call, move, and
95 // destroy pointers.
96 using CallbackPointerUnionT =
97 PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
98
99 // The main storage buffer. This will either have a pointer to out-of-line
100 // storage or an inline buffer storing the callable.
101 union StorageUnionT {
102 // For out-of-line storage we keep a pointer to the underlying storage and
103 // the size. This is enough to deallocate the memory.
104 struct OutOfLineStorageT {
105 void *StoragePtr;
106 size_t Size;
107 size_t Alignment;
108 } OutOfLineStorage;
109 static_assert(
110 sizeof(OutOfLineStorageT) <= InlineStorageSize,
111 "Should always use all of the out-of-line storage for inline storage!");
112
113 // For in-line storage, we just provide an aligned character buffer. We
114 // provide three pointers worth of storage here.
115 typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
116 InlineStorage;
117 } StorageUnion;
118
119 // A compressed pointer to either our dispatching callback or our table of
120 // dispatching callbacks and the flag for whether the callable itself is
121 // stored inline or not.
122 PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
123
124 bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
125
126 bool isTrivialCallback() const {
127 return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
128 }
129
130 CallPtrT getTrivialCallback() const {
131 return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
132 }
133
134 NonTrivialCallbacks *getNonTrivialCallbacks() const {
135 return CallbackAndInlineFlag.getPointer()
136 .template get<NonTrivialCallbacks *>();
137 }
138
139 void *getInlineStorage() { return &StorageUnion.InlineStorage; }
140
141 void *getOutOfLineStorage() {
142 return StorageUnion.OutOfLineStorage.StoragePtr;
20
Undefined or garbage value returned to caller
143 }
144 size_t getOutOfLineStorageSize() const {
145 return StorageUnion.OutOfLineStorage.Size;
146 }
147 size_t getOutOfLineStorageAlignment() const {
148 return StorageUnion.OutOfLineStorage.Alignment;
149 }
150
151 void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
152 StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
153 }
154
155 template <typename CallableT>
156 static ReturnT CallImpl(void *CallableAddr, AdjustedParamT<ParamTs>... Params) {
157 return (*reinterpret_cast<CallableT *>(CallableAddr))(
158 std::forward<ParamTs>(Params)...);
159 }
160
161 template <typename CallableT>
162 static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
163 new (LHSCallableAddr)
164 CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
165 }
166
167 template <typename CallableT>
168 static void DestroyImpl(void *CallableAddr) noexcept {
169 reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
170 }
171
172public:
173 unique_function() = default;
2
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
174 unique_function(std::nullptr_t /*null_callable*/) {}
175
176 ~unique_function() {
177 if (!CallbackAndInlineFlag.getPointer())
178 return;
179
180 // Cache this value so we don't re-check it after type-erased operations.
181 bool IsInlineStorage = isInlineStorage();
182
183 if (!isTrivialCallback())
184 getNonTrivialCallbacks()->DestroyPtr(
185 IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
186
187 if (!IsInlineStorage)
188 deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
189 getOutOfLineStorageAlignment());
190 }
191
192 unique_function(unique_function &&RHS) noexcept {
193 // Copy the callback and inline flag.
194 CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
195
196 // If the RHS is empty, just copying the above is sufficient.
197 if (!RHS)
11
Taking true branch
198 return;
12
Returning without writing to 'this->StorageUnion.OutOfLineStorage.StoragePtr'
199
200 if (!isInlineStorage()) {
201 // The out-of-line case is easiest to move.
202 StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
203 } else if (isTrivialCallback()) {
204 // Move is trivial, just memcpy the bytes across.
205 memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
206 } else {
207 // Non-trivial move, so dispatch to a type-erased implementation.
208 getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
209 RHS.getInlineStorage());
210 }
211
212 // Clear the old callback and inline flag to get back to as-if-null.
213 RHS.CallbackAndInlineFlag = {};
214
215#ifndef NDEBUG
216 // In debug builds, we also scribble across the rest of the storage.
217 memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
218#endif
219 }
220
221 unique_function &operator=(unique_function &&RHS) noexcept {
222 if (this == &RHS)
7
Taking false branch
223 return *this;
224
225 // Because we don't try to provide any exception safety guarantees we can
226 // implement move assignment very simply by first destroying the current
227 // object and then move-constructing over top of it.
228 this->~unique_function();
229 new (this) unique_function(std::move(RHS));
8
Calling 'operator new'
9
Returning from 'operator new'
10
Calling move constructor for 'unique_function<llvm::Error (unsigned long)>'
13
Returning from move constructor for 'unique_function<llvm::Error (unsigned long)>'
230 return *this;
231 }
232
233 template <typename CallableT> unique_function(CallableT Callable) {
234 bool IsInlineStorage = true;
235 void *CallableAddr = getInlineStorage();
236 if (sizeof(CallableT) > InlineStorageSize ||
237 alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
238 IsInlineStorage = false;
239 // Allocate out-of-line storage. FIXME: Use an explicit alignment
240 // parameter in C++17 mode.
241 auto Size = sizeof(CallableT);
242 auto Alignment = alignof(CallableT);
243 CallableAddr = allocate_buffer(Size, Alignment);
244 setOutOfLineStorage(CallableAddr, Size, Alignment);
245 }
246
247 // Now move into the storage.
248 new (CallableAddr) CallableT(std::move(Callable));
249
250 // See if we can create a trivial callback. We need the callable to be
251 // trivially moved and trivially destroyed so that we don't have to store
252 // type erased callbacks for those operations.
253 //
254 // FIXME: We should use constexpr if here and below to avoid instantiating
255 // the non-trivial static objects when unnecessary. While the linker should
256 // remove them, it is still wasteful.
257 if (llvm::is_trivially_move_constructible<CallableT>::value &&
258 std::is_trivially_destructible<CallableT>::value) {
259 // We need to create a nicely aligned object. We use a static variable
260 // for this because it is a trivial struct.
261 static TrivialCallback Callback = { &CallImpl<CallableT> };
262
263 CallbackAndInlineFlag = {&Callback, IsInlineStorage};
264 return;
265 }
266
267 // Otherwise, we need to point at an object that contains all the different
268 // type erased behaviors needed. Create a static instance of the struct type
269 // here and then use a pointer to that.
270 static NonTrivialCallbacks Callbacks = {
271 &CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
272
273 CallbackAndInlineFlag = {&Callbacks, IsInlineStorage};
274 }
275
276 ReturnT operator()(ParamTs... Params) {
277 void *CallableAddr =
278 isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
17
Assuming the condition is false
18
'?' condition is false
19
Calling 'unique_function::getOutOfLineStorage'
279
280 return (isTrivialCallback()
281 ? getTrivialCallback()
282 : getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...);
283 }
284
285 explicit operator bool() const {
286 return (bool)CallbackAndInlineFlag.getPointer();
287 }
288};
289
290} // end namespace llvm
291
292#endif // LLVM_ADT_FUNCTION_H