[libc-commits] [libc] 11112ed - [libc] Make cpp::expected::operator bool explicit (#208681)

via libc-commits libc-commits at lists.llvm.org
Sun Jul 12 22:36:29 PDT 2026


Author: Pavel Labath
Date: 2026-07-13T07:36:24+02:00
New Revision: 11112ed9b7eb7deb69b97178a0c4921e6222049c

URL: https://github.com/llvm/llvm-project/commit/11112ed9b7eb7deb69b97178a0c4921e6222049c
DIFF: https://github.com/llvm/llvm-project/commit/11112ed9b7eb7deb69b97178a0c4921e6222049c.diff

LOG: [libc] Make cpp::expected::operator bool explicit (#208681)

Without explicit, expected<T, E> implicitly converts to bool in all
sorts of unexpected contexts (e.g. `EXPECT_EQ(ErrorOr<int>(47), 1)`),
and also deviates from std::expected in C++23.

While in there, add basic unit tests for expected and unexpected (we
didn't have any tests for this utility yet), and update the file header.

Assisted by Gemini.

Added: 
    libc/test/src/__support/CPP/expected_test.cpp

Modified: 
    libc/src/__support/CPP/expected.h
    libc/test/src/__support/CPP/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CPP/expected.h b/libc/src/__support/CPP/expected.h
index 8a93091f0ebfb..d416422ba2b50 100644
--- a/libc/src/__support/CPP/expected.h
+++ b/libc/src/__support/CPP/expected.h
@@ -1,10 +1,15 @@
-//===-- Holds an expected or unexpected value -------------------*- C++ -*-===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implementation of C++23-style expected and unexpected utilities.
+///
+//===----------------------------------------------------------------------===//
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_EXPECTED_H
 #define LLVM_LIBC_SRC___SUPPORT_CPP_EXPECTED_H
@@ -46,7 +51,7 @@ template <class T, class E> class expected {
   LIBC_INLINE constexpr const T &value() const { return exp; }
   LIBC_INLINE constexpr const E &error() const { return unexp; }
 
-  LIBC_INLINE constexpr operator bool() const { return is_expected; }
+  LIBC_INLINE constexpr explicit operator bool() const { return is_expected; }
 
   LIBC_INLINE constexpr T &operator*() { return exp; }
   LIBC_INLINE constexpr const T &operator*() const { return exp; }

diff  --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index c9d405710007b..ac0e8289e64bd 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -53,6 +53,17 @@ add_libc_test(
     libc.src.__support.CPP.cstddef
 )
 
+add_libc_test(
+  expected_test
+  SUITE
+    libc-cpp-utils-tests
+  SRCS
+    expected_test.cpp
+  DEPENDS
+    libc.src.__support.CPP.expected
+    libc.src.__support.CPP.type_traits
+)
+
 add_libc_test(
   stringview_test
   SUITE

diff  --git a/libc/test/src/__support/CPP/expected_test.cpp b/libc/test/src/__support/CPP/expected_test.cpp
new file mode 100644
index 0000000000000..21ff1d6159ff4
--- /dev/null
+++ b/libc/test/src/__support/CPP/expected_test.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Unit tests for LIBC_NAMESPACE::cpp::expected and unexpected.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/expected.h"
+#include "src/__support/CPP/type_traits.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::cpp::expected;
+using LIBC_NAMESPACE::cpp::unexpected;
+
+TEST(LlvmLibcExpectedTest, Unexpected) {
+  unexpected<int> u1(42);
+  ASSERT_EQ(u1.error(), 42);
+}
+
+TEST(LlvmLibcExpectedTest, ValueConstruction) {
+  expected<int, double> e(123);
+  ASSERT_TRUE(e.has_value());
+  ASSERT_TRUE(static_cast<bool>(e));
+  ASSERT_EQ(e.value(), 123);
+  ASSERT_EQ(*e, 123);
+}
+
+TEST(LlvmLibcExpectedTest, ErrorConstruction) {
+  expected<int, int> e(unexpected(404));
+  ASSERT_FALSE(e.has_value());
+  ASSERT_FALSE(static_cast<bool>(e));
+  ASSERT_EQ(e.error(), 404);
+}
+
+TEST(LlvmLibcExpectedTest, Mutation) {
+  expected<int, int> e(10);
+  ASSERT_EQ(e.value(), 10);
+  e.value() = 20;
+  ASSERT_EQ(e.value(), 20);
+  *e = 30;
+  ASSERT_EQ(*e, 30);
+
+  expected<int, int> u(unexpected<int>(1));
+  ASSERT_EQ(u.error(), 1);
+  u.error() = 2;
+  ASSERT_EQ(u.error(), 2);
+}
+
+TEST(LlvmLibcExpectedTest, ConstAccess) {
+  const expected<int, int> CE(100);
+  ASSERT_TRUE(CE.has_value());
+  ASSERT_TRUE(static_cast<bool>(CE));
+  ASSERT_EQ(CE.value(), 100);
+  ASSERT_EQ(*CE, 100);
+
+  const expected<int, int> CU(unexpected(500));
+  ASSERT_FALSE(CU.has_value());
+  ASSERT_FALSE(static_cast<bool>(CU));
+  ASSERT_EQ(CU.error(), 500);
+}
+
+struct Foo {
+  int x;
+  int get_x() const { return x; }
+  void set_x(int new_x) { x = new_x; }
+};
+
+TEST(LlvmLibcExpectedTest, ArrowOperator) {
+  expected<Foo, int> e(Foo{42});
+  ASSERT_TRUE(e.has_value());
+  ASSERT_EQ(e->x, 42);
+  ASSERT_EQ(e->get_x(), 42);
+  e->set_x(99);
+  ASSERT_EQ(e->x, 99);
+
+  const expected<Foo, int> CE(Foo{123});
+  ASSERT_EQ(CE->x, 123);
+  ASSERT_EQ(CE->get_x(), 123);
+}
+
+constexpr bool test_constexpr_value() {
+  expected<int, int> e(42);
+  if (!e.has_value() || !static_cast<bool>(e))
+    return false;
+  if (e.value() != 42 || *e != 42)
+    return false;
+  return true;
+}
+
+static_assert(test_constexpr_value(), "expected constexpr value check failed");
+
+constexpr bool test_constexpr_error() {
+  expected<int, int> e(unexpected<int>(99));
+  if (e.has_value() || static_cast<bool>(e))
+    return false;
+  if (e.error() != 99)
+    return false;
+  return true;
+}
+
+static_assert(test_constexpr_error(), "expected constexpr error check failed");
+
+static_assert(!LIBC_NAMESPACE::cpp::is_convertible_v<expected<int, long>, bool>,
+              "only explicit conversions allowed");


        


More information about the libc-commits mailing list