Bug Summary

File:lldb/source/Utility/SelectHelper.cpp
Warning:line 246, column 15
Array access (via field 'fds_bits') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name SelectHelper.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 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D HAVE_ROUND -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lldb/source/Utility -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source/Utility -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/include -I tools/lldb/../clang/include -I /usr/include/libxml2 -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source -I tools/lldb/source -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -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-2022-01-19-134126-35450-1 -x c++ /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source/Utility/SelectHelper.cpp

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source/Utility/SelectHelper.cpp

1//===-- SelectHelper.cpp --------------------------------------------------===//
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#if defined(__APPLE__)
10// Enable this special support for Apple builds where we can have unlimited
11// select bounds. We tried switching to poll() and kqueue and we were panicing
12// the kernel, so we have to stick with select for now.
13#define _DARWIN_UNLIMITED_SELECT
14#endif
15
16#include "lldb/Utility/SelectHelper.h"
17#include "lldb/Utility/LLDBAssert.h"
18#include "lldb/Utility/Status.h"
19#include "lldb/lldb-enumerations.h"
20#include "lldb/lldb-types.h"
21
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/Optional.h"
24
25#include <algorithm>
26#include <chrono>
27
28#include <cerrno>
29#if defined(_WIN32)
30// Define NOMINMAX to avoid macros that conflict with std::min and std::max
31#define NOMINMAX
32#include <winsock2.h>
33#else
34#include <sys/time.h>
35#include <sys/select.h>
36#endif
37
38
39SelectHelper::SelectHelper()
40 : m_fd_map(), m_end_time() // Infinite timeout unless
41 // SelectHelper::SetTimeout() gets called
42{}
43
44void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) {
45 using namespace std::chrono;
46 m_end_time = steady_clock::time_point(steady_clock::now() + timeout);
47}
48
49void SelectHelper::FDSetRead(lldb::socket_t fd) {
50 m_fd_map[fd].read_set = true;
51}
52
53void SelectHelper::FDSetWrite(lldb::socket_t fd) {
54 m_fd_map[fd].write_set = true;
55}
56
57void SelectHelper::FDSetError(lldb::socket_t fd) {
58 m_fd_map[fd].error_set = true;
59}
60
61bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const {
62 auto pos = m_fd_map.find(fd);
63 if (pos != m_fd_map.end())
64 return pos->second.read_is_set;
65 else
66 return false;
67}
68
69bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const {
70 auto pos = m_fd_map.find(fd);
71 if (pos != m_fd_map.end())
72 return pos->second.write_is_set;
73 else
74 return false;
75}
76
77bool SelectHelper::FDIsSetError(lldb::socket_t fd) const {
78 auto pos = m_fd_map.find(fd);
79 if (pos != m_fd_map.end())
80 return pos->second.error_is_set;
81 else
82 return false;
83}
84
85static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold,
86 lldb::socket_t vnew) {
87 if (!vold.hasValue())
10
Taking true branch
88 vold = vnew;
89 else
90 vold = std::max(*vold, vnew);
91}
92
93lldb_private::Status SelectHelper::Select() {
94 lldb_private::Status error;
95#ifdef _WIN32
96 // On windows FD_SETSIZE limits the number of file descriptors, not their
97 // numeric value.
98 lldbassert(m_fd_map.size() <= FD_SETSIZE)lldb_private::lldb_assert(static_cast<bool>(m_fd_map.size
() <= 1024), "m_fd_map.size() <= FD_SETSIZE", __FUNCTION__
, "lldb/source/Utility/SelectHelper.cpp", 98)
;
99 if (m_fd_map.size() > FD_SETSIZE1024)
100 return lldb_private::Status("Too many file descriptors for select()");
101#endif
102
103 llvm::Optional<lldb::socket_t> max_read_fd;
104 llvm::Optional<lldb::socket_t> max_write_fd;
105 llvm::Optional<lldb::socket_t> max_error_fd;
106 llvm::Optional<lldb::socket_t> max_fd;
107 for (auto &pair : m_fd_map) {
108 pair.second.PrepareForSelect();
109 const lldb::socket_t fd = pair.first;
110#if !defined(__APPLE__) && !defined(_WIN32)
111 lldbassert(fd < static_cast<int>(FD_SETSIZE))lldb_private::lldb_assert(static_cast<bool>(fd < static_cast
<int>(1024)), "fd < static_cast<int>(FD_SETSIZE)"
, __FUNCTION__, "lldb/source/Utility/SelectHelper.cpp", 111)
;
1
Assuming 'fd' is < 1024
112 if (fd
1.1
'fd' is < 1024
1.1
'fd' is < 1024
>= static_cast<int>(FD_SETSIZE1024)) {
2
Taking false branch
113 error.SetErrorStringWithFormat("%i is too large for select()", fd);
114 return error;
115 }
116#endif
117 if (pair.second.read_set)
3
Assuming field 'read_set' is false
4
Taking false branch
118 updateMaxFd(max_read_fd, fd);
119 if (pair.second.write_set)
5
Assuming field 'write_set' is false
6
Taking false branch
120 updateMaxFd(max_write_fd, fd);
121 if (pair.second.error_set)
7
Assuming field 'error_set' is false
8
Taking false branch
122 updateMaxFd(max_error_fd, fd);
123 updateMaxFd(max_fd, fd);
9
Calling 'updateMaxFd'
11
Returning from 'updateMaxFd'
124 }
125
126 if (!max_fd.hasValue()) {
12
Calling 'Optional::hasValue'
17
Returning from 'Optional::hasValue'
18
Taking false branch
127 error.SetErrorString("no valid file descriptors");
128 return error;
129 }
130
131 const unsigned nfds = static_cast<unsigned>(*max_fd) + 1;
132 fd_set *read_fdset_ptr = nullptr;
133 fd_set *write_fdset_ptr = nullptr;
134 fd_set *error_fdset_ptr = nullptr;
19
'error_fdset_ptr' initialized to a null pointer value
135// Initialize and zero out the fdsets
136#if defined(__APPLE__)
137 llvm::SmallVector<fd_set, 1> read_fdset;
138 llvm::SmallVector<fd_set, 1> write_fdset;
139 llvm::SmallVector<fd_set, 1> error_fdset;
140
141 if (max_read_fd.hasValue()) {
142 read_fdset.resize((nfds / FD_SETSIZE1024) + 1);
143 read_fdset_ptr = read_fdset.data();
144 }
145 if (max_write_fd.hasValue()) {
146 write_fdset.resize((nfds / FD_SETSIZE1024) + 1);
147 write_fdset_ptr = write_fdset.data();
148 }
149 if (max_error_fd.hasValue()) {
150 error_fdset.resize((nfds / FD_SETSIZE1024) + 1);
151 error_fdset_ptr = error_fdset.data();
152 }
153 for (auto &fd_set : read_fdset)
154 FD_ZERO(&fd_set)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&fd_set)->fds_bits)[
0]) : "memory"); } while (0)
;
155 for (auto &fd_set : write_fdset)
156 FD_ZERO(&fd_set)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&fd_set)->fds_bits)[
0]) : "memory"); } while (0)
;
157 for (auto &fd_set : error_fdset)
158 FD_ZERO(&fd_set)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&fd_set)->fds_bits)[
0]) : "memory"); } while (0)
;
159#else
160 fd_set read_fdset;
161 fd_set write_fdset;
162 fd_set error_fdset;
163
164 if (max_read_fd.hasValue()) {
20
Taking false branch
165 FD_ZERO(&read_fdset)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&read_fdset)->fds_bits
)[0]) : "memory"); } while (0)
;
166 read_fdset_ptr = &read_fdset;
167 }
168 if (max_write_fd.hasValue()) {
21
Taking false branch
169 FD_ZERO(&write_fdset)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&write_fdset)->fds_bits
)[0]) : "memory"); } while (0)
;
170 write_fdset_ptr = &write_fdset;
171 }
172 if (max_error_fd.hasValue()) {
22
Taking false branch
173 FD_ZERO(&error_fdset)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq"
: "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) /
sizeof (__fd_mask)), "1" (&((&error_fdset)->fds_bits
)[0]) : "memory"); } while (0)
;
174 error_fdset_ptr = &error_fdset;
175 }
176#endif
177 // Set the FD bits in the fdsets for read/write/error
178 for (auto &pair : m_fd_map) {
179 const lldb::socket_t fd = pair.first;
180
181 if (pair.second.read_set)
182 FD_SET(fd, read_fdset_ptr)((void) (((read_fdset_ptr)->fds_bits)[__extension__ ({ long
int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d &&
__d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn
(__d)) : __fdelt_chk (__d)); })] |= ((__fd_mask) (1UL <<
((fd) % (8 * (int) sizeof (__fd_mask)))))))
;
183
184 if (pair.second.write_set)
185 FD_SET(fd, write_fdset_ptr)((void) (((write_fdset_ptr)->fds_bits)[__extension__ ({ long
int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d &&
__d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn
(__d)) : __fdelt_chk (__d)); })] |= ((__fd_mask) (1UL <<
((fd) % (8 * (int) sizeof (__fd_mask)))))))
;
186
187 if (pair.second.error_set)
188 FD_SET(fd, error_fdset_ptr)((void) (((error_fdset_ptr)->fds_bits)[__extension__ ({ long
int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d &&
__d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn
(__d)) : __fdelt_chk (__d)); })] |= ((__fd_mask) (1UL <<
((fd) % (8 * (int) sizeof (__fd_mask)))))))
;
189 }
190
191 // Setup our timeout time value if needed
192 struct timeval *tv_ptr = nullptr;
193 struct timeval tv = {0, 0};
194
195 while (true) {
23
Loop condition is true. Entering loop body
196 using namespace std::chrono;
197 // Setup out relative timeout based on the end time if we have one
198 if (m_end_time.hasValue()) {
24
Assuming the condition is false
25
Taking false branch
199 tv_ptr = &tv;
200 const auto remaining_dur = duration_cast<microseconds>(
201 m_end_time.getValue() - steady_clock::now());
202 if (remaining_dur.count() > 0) {
203 // Wait for a specific amount of time
204 const auto dur_secs = duration_cast<seconds>(remaining_dur);
205 const auto dur_usecs = remaining_dur % seconds(1);
206 tv.tv_sec = dur_secs.count();
207 tv.tv_usec = dur_usecs.count();
208 } else {
209 // Just poll once with no timeout
210 tv.tv_sec = 0;
211 tv.tv_usec = 0;
212 }
213 }
214 const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
215 error_fdset_ptr, tv_ptr);
216 if (num_set_fds < 0) {
26
Assuming 'num_set_fds' is >= 0
27
Taking false branch
217 // We got an error
218 error.SetErrorToErrno();
219 if (error.GetError() == EINTR4) {
220 error.Clear();
221 continue; // Keep calling select if we get EINTR
222 } else
223 return error;
224 } else if (num_set_fds == 0) {
28
Assuming 'num_set_fds' is not equal to 0
29
Taking false branch
225 // Timeout
226 error.SetError(ETIMEDOUT110, lldb::eErrorTypePOSIX);
227 error.SetErrorString("timed out");
228 return error;
229 } else {
230 // One or more descriptors were set, update the FDInfo::select_is_set
231 // mask so users can ask the SelectHelper class so clients can call one
232 // of:
233
234 for (auto &pair : m_fd_map) {
235 const int fd = pair.first;
236
237 if (pair.second.read_set) {
30
Assuming field 'read_set' is false
31
Taking false branch
238 if (FD_ISSET(fd, read_fdset_ptr)((((read_fdset_ptr)->fds_bits)[__extension__ ({ long int __d
= (fd); (__builtin_constant_p (__d) ? (0 <= __d &&
__d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn
(__d)) : __fdelt_chk (__d)); })] & ((__fd_mask) (1UL <<
((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)
)
239 pair.second.read_is_set = true;
240 }
241 if (pair.second.write_set) {
32
Assuming field 'write_set' is false
33
Taking false branch
242 if (FD_ISSET(fd, write_fdset_ptr)((((write_fdset_ptr)->fds_bits)[__extension__ ({ long int __d
= (fd); (__builtin_constant_p (__d) ? (0 <= __d &&
__d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn
(__d)) : __fdelt_chk (__d)); })] & ((__fd_mask) (1UL <<
((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)
)
243 pair.second.write_is_set = true;
244 }
245 if (pair.second.error_set) {
34
Assuming field 'error_set' is true
35
Taking true branch
246 if (FD_ISSET(fd, error_fdset_ptr)((((error_fdset_ptr)->fds_bits)[__extension__ ({ long int __d
= (fd); (__builtin_constant_p (__d) ? (0 <= __d &&
__d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn
(__d)) : __fdelt_chk (__d)); })] & ((__fd_mask) (1UL <<
((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)
)
36
'?' condition is false
37
Array access (via field 'fds_bits') results in a null pointer dereference
247 pair.second.error_is_set = true;
248 }
249 }
250 break;
251 }
252 }
253 return error;
254}

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/llvm/include/llvm/ADT/Optional.h

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