From c56d69ebf93526869898537ca142310cfd448a97 Mon Sep 17 00:00:00 2001 From: Artyom Kolpakov Date: Mon, 27 Apr 2026 20:40:48 +0000 Subject: [PATCH] fix universal: disable initialization of Required with {} as the initializer-list --- universal/include/userver/utils/required.hpp | 7 ++++--- universal/src/utils/required_test.cpp | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/universal/include/userver/utils/required.hpp b/universal/include/userver/utils/required.hpp index 5ffaf2e1ab43..fac62e77c9c3 100644 --- a/universal/include/userver/utils/required.hpp +++ b/universal/include/userver/utils/required.hpp @@ -4,6 +4,7 @@ /// @brief @copybrief utils::Required #include +#include #include #include #include @@ -31,7 +32,7 @@ class Required final { Required() = delete; /// @brief Construct `T` from a value (conditionally explicit). - template + template requires(!std::same_as, Required> && std::constructible_from) constexpr explicit(!std::convertible_to) Required(U&& value) : value_(std::forward(value)) @@ -59,10 +60,10 @@ class Required final { constexpr T&& operator*() && noexcept { return std::move(value_); } /// @brief Access members of the contained value. - constexpr T* operator->() noexcept USERVER_IMPL_LIFETIME_BOUND { return &value_; } + constexpr T* operator->() noexcept USERVER_IMPL_LIFETIME_BOUND { return std::addressof(value_); } /// @overload - constexpr const T* operator->() const noexcept USERVER_IMPL_LIFETIME_BOUND { return &value_; } + constexpr const T* operator->() const noexcept USERVER_IMPL_LIFETIME_BOUND { return std::addressof(value_); } /// @brief Implicit conversion to `T&`. constexpr /*implicit*/ operator T&() & noexcept USERVER_IMPL_LIFETIME_BOUND { return value_; } diff --git a/universal/src/utils/required_test.cpp b/universal/src/utils/required_test.cpp index 615679dc98b1..09f1fbd7579a 100644 --- a/universal/src/utils/required_test.cpp +++ b/universal/src/utils/required_test.cpp @@ -87,6 +87,19 @@ TEST(UtilsRequired, DerefMove) { EXPECT_EQ(moved, "move-me"); } +TEST(UtilsRequired, DerefAddressof) { + struct Overloaded { + bool used = false; + auto operator&() { + used = true; + return this; + } + }; + + utils::Required r{false}; + EXPECT_FALSE(r->used); +} + TEST(UtilsRequired, Mutate) { utils::Required r{"initial"}; *r = "modified";