aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2023-07-03 22:17:06 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2023-07-03 22:17:06 +0200
commit6b062584e56fe395be723220324ea384bf447971 (patch)
tree604b80b2fd8f9e5a2dcd5fda5e51920a7acb119d
parent07c77d4c24177ac3e11cafd27f34c9a758008db6 (diff)
downloadcpp-utils-6b062584e56fe395be723220324ea384bf447971.tar.gz
cpp-utils-6b062584e56fe395be723220324ea384bf447971.zip
option: fix UB, launder value ptr
-rw-r--r--option.h19
1 files changed, 16 insertions, 3 deletions
diff --git a/option.h b/option.h
index b9ebe2f..fd26acb 100644
--- a/option.h
+++ b/option.h
@@ -18,7 +18,7 @@ using enable_if_t = typename std::enable_if<Cond, T>::type;
/// The NONE type.
struct none {};
-// The OPTION type.
+/// The OPTION type.
template <typename T>
struct option {
static_assert(!std::is_reference<T>::value, "T must not be a reference type");
@@ -87,12 +87,25 @@ struct option {
constexpr T& value() & {
assert(m_has_value);
- return *reinterpret_cast<T*>(m_value);
+ // Launder pointer, this informs the compiler that certain optimizations are
+ // not applicable such as CONSTPROP. This is required because every use
+ // of PLACEMENT new on M_VALUE starts a new LIFETIME and returning a
+ // pointer based on the LIFETIME of M_VALUE is UB [1][2].
+ //
+ // Notes:
+ // * Obtaining a pointer to an object created by placement new from a
+ // pointer to an object providing storage for that object [1].
+ // * See example in [1] and [2].
+ //
+ // [1]: https://en.cppreference.com/w/cpp/utility/launder
+ // [2]: https://en.cppreference.com/w/cpp/types/aligned_storage
+ return *__builtin_launder(reinterpret_cast<T*>(m_value));
}
constexpr const T& value() const& {
assert(m_has_value);
- return *reinterpret_cast<const T*>(m_value);
+ // Launder, see other value().
+ return *__builtin_launder(reinterpret_cast<const T*>(m_value));
}
constexpr T value() && {