[libcxx-commits] [libcxx] [libc++] Mark std::expected as nodiscard (PR #139651)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun May 25 20:33:43 PDT 2025


https://github.com/halbi2 updated https://github.com/llvm/llvm-project/pull/139651

>From e47e69c3ca38f13988d56e25cb6a78467b21f44d Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Mon, 12 May 2025 20:57:00 -0400
Subject: [PATCH 1/5] [libc++] Mark std::expected as nodiscard

Fixes #130656
---
 libcxx/include/__expected/expected.h          |  4 ++--
 .../and_then.mandates.verify.cpp              | 16 ++++++-------
 .../expected.expected/nodiscard.verify.cpp    | 23 +++++++++++++++++++
 .../or_else.mandates.verify.cpp               | 16 ++++++-------
 .../transform_error.mandates.verify.cpp       | 16 ++++++-------
 .../and_then.mandates.verify.cpp              | 16 ++++++-------
 .../expected.void/or_else.mandates.verify.cpp | 16 ++++++-------
 .../transform_error.mandates.verify.cpp       | 16 ++++++-------
 8 files changed, 73 insertions(+), 50 deletions(-)
 create mode 100644 libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp

diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 0f446b870723b..1ecf46c879bd6 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -448,7 +448,7 @@ class __expected_base {
 };
 
 template <class _Tp, class _Err>
-class expected : private __expected_base<_Tp, _Err> {
+class [[nodiscard]] expected : private __expected_base<_Tp, _Err> {
   static_assert(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, in_place_t> &&
                     !is_same_v<remove_cv_t<_Tp>, unexpect_t> && !__is_std_unexpected<remove_cv_t<_Tp>>::value &&
                     __valid_std_unexpected<_Err>::value,
@@ -1377,7 +1377,7 @@ class __expected_void_base {
 
 template <class _Tp, class _Err>
   requires is_void_v<_Tp>
-class expected<_Tp, _Err> : private __expected_void_base<_Err> {
+class [[nodiscard]] expected<_Tp, _Err> : private __expected_void_base<_Err> {
   static_assert(__valid_std_unexpected<_Err>::value,
                 "[expected.void.general] A program that instantiates expected<T, E> with a E that is not a "
                 "valid argument for unexpected<E> is ill-formed");
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
index c46ab633295c1..7c95fc19cd693 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
@@ -51,7 +51,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       std::expected<int, int> f1(1);
-      f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(int &)>' requested here}}
+      (void)f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -60,7 +60,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       std::expected<int, int> f1(1);
-      f1.and_then(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(int &)>' requested here}}
+      (void)f1.and_then(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must have the same error_type as this expected}}
     }
   }
@@ -70,7 +70,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       const std::expected<int, int> f1(1);
-      f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(const int &)>' requested here}}
+      (void)f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(const int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -79,7 +79,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       const std::expected<int, int> f1(1);
-      f1.and_then(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(const int &)>' requested here}}
+      (void)f1.and_then(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(const int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must have the same error_type as this expected}}
 
     }
@@ -90,7 +90,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       std::expected<int, int> f1(1);
-      std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(int &&)>' requested here}}
+      (void)std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -99,7 +99,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       std::expected<int, int> f1(1);
-      std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(int &&)>' requested here}}
+      (void)std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}}
     }
   }
@@ -109,7 +109,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       const std::expected<int, int> f1(1);
-      std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(const int &&)>' requested here}}
+      (void)std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(const int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -118,7 +118,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       const std::expected<int, int> f1(1);
-      std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(const int &&)>' requested here}}
+      (void)std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(const int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}}
     }
   }
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
new file mode 100644
index 0000000000000..ea5d51cdf051c
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// <expected>
+
+// Test that ignoring std::expected generates [[nodiscard]] warnings.
+
+#include <expected>
+
+std::expected<int, int> returns_expected();
+std::expected<void, int> returns_expected_void();
+
+void test() {
+  returns_expected(); // expected-warning {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void(); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
+}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
index af1fa53307960..8064463977e48 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
@@ -51,7 +51,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       std::expected<int, int> f1(std::unexpected<int>(1));
-      f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(int &)>' requested here}}
+      (void)f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -60,7 +60,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       std::expected<int, int> f1(std::unexpected<int>(1));
-      f1.or_else(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &)>' requested here}}
+      (void)f1.or_else(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
     }
   }
@@ -70,7 +70,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       const std::expected<int, int> f1(std::unexpected<int>(1));
-      f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(const int &)>' requested here}}
+      (void)f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(const int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -79,7 +79,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       const std::expected<int, int> f1(std::unexpected<int>(1));
-      f1.or_else(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &)>' requested here}}
+      (void)f1.or_else(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
     }
   }
@@ -89,7 +89,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       std::expected<int, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(int &&)>' requested here}}
+      (void)std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -98,7 +98,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       std::expected<int, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &&)>' requested here}}
+      (void)std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
     }
   }
@@ -108,7 +108,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       const std::expected<int, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(const int &&)>' requested here}}
+      (void)std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(const int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -117,7 +117,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       const std::expected<int, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &&)>' requested here}}
+      (void)std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
     }
   }
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
index 61374094b7adf..4c8b4999375af 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/transform_error.mandates.verify.cpp
@@ -58,12 +58,12 @@ void test() {
   // Test & overload
   {
     std::expected<int, int> e;
-    e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
     // expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
 
-    e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
     // expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
@@ -72,27 +72,27 @@ void test() {
   // Test const& overload
   {
     const std::expected<int, int> e;
-    e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test && overload
   {
     std::expected<int, int> e;
-    std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test const&& overload
   {
     const std::expected<int, int> e;
-    std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 }
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp
index e1a7ec5ff4d72..92713f0f78148 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/and_then.mandates.verify.cpp
@@ -51,7 +51,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       std::expected<void, int> f1;
-      f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
+      (void)f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -60,7 +60,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       std::expected<void, int> f1;
-      f1.and_then(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
+      (void)f1.and_then(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must have the same error_type as this expected}}
     }
   }
@@ -70,7 +70,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       const std::expected<void, int> f1;
-      f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
+      (void)f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -79,7 +79,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       const std::expected<void, int> f1;
-      f1.and_then(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
+      (void)f1.and_then(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must have the same error_type as this expected}}
     }
   }
@@ -89,7 +89,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       std::expected<void, int> f1;
-      std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
+      (void)std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -98,7 +98,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       std::expected<void, int> f1;
-      std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
+      (void)std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must have the same error_type as this expected}}
     }
   }
@@ -108,7 +108,7 @@ void test() {
     // U is not a specialization of std::expected
     {
       const std::expected<void, int> f1;
-      std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
+      (void)std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
       // expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
@@ -117,7 +117,7 @@ void test() {
     // !std::is_same_v<U:error_type, E>
     {
       const std::expected<void, int> f1;
-      std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
+      (void)std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f() must have the same error_type as this expected}}
     }
   }
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp
index 3046d09d6af55..7916290f253c3 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/or_else.mandates.verify.cpp
@@ -51,7 +51,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       std::expected<void, int> f1(std::unexpected<int>(1));
-      f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(int &)>' requested here}}
+      (void)f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
     }
@@ -59,7 +59,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       std::expected<void, int> f1(std::unexpected<int>(1));
-      f1.or_else(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &)>' requested here}}
+      (void)f1.or_else(lval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
     }
   }
@@ -69,7 +69,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       const std::expected<void, int> f1(std::unexpected<int>(1));
-      f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(const int &)>' requested here}}
+      (void)f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(const int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
     }
@@ -77,7 +77,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       const std::expected<void, int> f1(std::unexpected<int>(1));
-      f1.or_else(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &)>' requested here}}
+      (void)f1.or_else(clval_error_type_not_same_as_int);  // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
     }
   }
@@ -87,7 +87,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       std::expected<void, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(int &&)>' requested here}}
+      (void)std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
     }
@@ -95,7 +95,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       std::expected<void, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &&)>' requested here}}
+      (void)std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
     }
   }
@@ -105,7 +105,7 @@ void test() {
     // G is not a specialization of std::expected
     {
       const std::expected<void, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(const int &&)>' requested here}}
+      (void)std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(const int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
       // expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
     }
@@ -113,7 +113,7 @@ void test() {
     // !std::is_same_v<G:value_type, T>
     {
       const std::expected<void, int> f1(std::unexpected<int>(1));
-      std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &&)>' requested here}}
+      (void)std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &&)>' requested here}}
       // expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
     }
   }
diff --git a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
index 16233cd90d219..78654aa24a916 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.void/transform_error.mandates.verify.cpp
@@ -59,13 +59,13 @@ void test() {
   // Test & overload
   {
     std::expected<void, int> e;
-    e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
     // expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
     // expected-error-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}}}
 
-    e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* {{static assertion failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
     // expected-warning-re@*:* 0-1 {{union member {{.*}} has reference type {{.*}}, which is a Microsoft extension}}
@@ -74,9 +74,9 @@ void test() {
   // Test const& overload
   {
     const std::expected<void, int> e;
-    e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
     // expected-error-re@*:* 0-1 {{call to deleted constructor of {{.*}}}}
   }
@@ -84,18 +84,18 @@ void test() {
   // Test && overload
   {
     std::expected<void, int> e;
-    std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 
   // Test const&& overload
   {
     const std::expected<void, int> e;
-    std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
-    std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
+    (void)std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{static assertion failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
     // expected-error-re@*:* 0-1 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
   }
 }

>From b47f10c833a4e2009a24a383e710e308b277d6b7 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Mon, 12 May 2025 21:14:11 -0400
Subject: [PATCH 2/5] fix clang-format

---
 .../utilities/expected/expected.expected/nodiscard.verify.cpp   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
index ea5d51cdf051c..5747a3ae257bb 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
@@ -18,6 +18,6 @@ std::expected<int, int> returns_expected();
 std::expected<void, int> returns_expected_void();
 
 void test() {
-  returns_expected(); // expected-warning {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected();      // expected-warning {{ignoring return value of type 'expected<int, int>'}}
   returns_expected_void(); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
 }

>From 5d963587c2bf36e8d47986a1d0828f44ada373c8 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Tue, 13 May 2025 10:22:49 -0400
Subject: [PATCH 3/5] Configurable with _LIBCPP_DISABLE_NODISCARD_EXPECTED

---
 libcxx/docs/UserDocumentation.rst             |  6 +++
 libcxx/include/__config                       |  6 +++
 libcxx/include/__expected/expected.h          |  4 +-
 .../expected.expected/nodiscard.verify.cpp    | 18 ++++++++
 .../expected.expected/nodiscard2.verify.cpp   | 44 +++++++++++++++++++
 5 files changed, 76 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard2.verify.cpp

diff --git a/libcxx/docs/UserDocumentation.rst b/libcxx/docs/UserDocumentation.rst
index dbacb44735d08..b5e9bc8889289 100644
--- a/libcxx/docs/UserDocumentation.rst
+++ b/libcxx/docs/UserDocumentation.rst
@@ -100,6 +100,12 @@ enable or disable extended libc++ behavior.
   warning saying that `std::auto_ptr` is deprecated. If the macro is defined,
   no warning will be emitted. By default, this macro is not defined.
 
+**_LIBCPP_DISABLE_NODISCARD_EXPECTED**:
+  This macro disables warnings when discarding the value of a `std::expected`
+  object without checking for error. If the macro is defined, no warning will
+  be emitted when discarding `std::expected`. By default, this macro is not
+  defined.
+
 **_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS**:
   This macro is used to disable all visibility annotations inside libc++.
   Defining this macro and then building libc++ with hidden visibility gives a
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 110450f6e9c51..3f2a34ffb3c68 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -352,6 +352,12 @@ typedef __char32_t char32_t;
 
 #  define _LIBCPP_ALWAYS_INLINE __attribute__((__always_inline__))
 
+#  if defined(_LIBCPP_DISABLE_NODISCARD_EXPECTED)
+#    define _LIBCPP_NODISCARD_EXPECTED
+#  else
+#    define _LIBCPP_NODISCARD_EXPECTED [[nodiscard]]
+#  endif
+
 #  if defined(_LIBCPP_OBJECT_FORMAT_COFF)
 
 #    ifdef _DLL
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index 1ecf46c879bd6..3331e8767f5aa 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -448,7 +448,7 @@ class __expected_base {
 };
 
 template <class _Tp, class _Err>
-class [[nodiscard]] expected : private __expected_base<_Tp, _Err> {
+class _LIBCPP_NODISCARD_EXPECTED expected : private __expected_base<_Tp, _Err> {
   static_assert(!is_reference_v<_Tp> && !is_function_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, in_place_t> &&
                     !is_same_v<remove_cv_t<_Tp>, unexpect_t> && !__is_std_unexpected<remove_cv_t<_Tp>>::value &&
                     __valid_std_unexpected<_Err>::value,
@@ -1377,7 +1377,7 @@ class __expected_void_base {
 
 template <class _Tp, class _Err>
   requires is_void_v<_Tp>
-class [[nodiscard]] expected<_Tp, _Err> : private __expected_void_base<_Err> {
+class _LIBCPP_NODISCARD_EXPECTED expected<_Tp, _Err> : private __expected_void_base<_Err> {
   static_assert(__valid_std_unexpected<_Err>::value,
                 "[expected.void.general] A program that instantiates expected<T, E> with a E that is not a "
                 "valid argument for unexpected<E> is ill-formed");
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
index 5747a3ae257bb..7d2170cbd0554 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
@@ -17,7 +17,25 @@
 std::expected<int, int> returns_expected();
 std::expected<void, int> returns_expected_void();
 
+std::expected<int, int> and_then(int);
+std::expected<void, int> and_then_void();
+std::expected<int, int> or_else(int);
+std::expected<void, int> or_else_void(int);
+int transform(int);
+void transform_void();
+int transform_error(int);
+int transform_error_void(int);
+
 void test() {
   returns_expected();      // expected-warning {{ignoring return value of type 'expected<int, int>'}}
   returns_expected_void(); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
+
+  returns_expected().and_then(and_then);                         // expected-warning {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().and_then(and_then_void);               // expected-warning {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().or_else(or_else);                           // expected-warning {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().or_else(or_else_void);                 // expected-warning {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().transform(transform);                       // expected-warning {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().transform(transform_void);             // expected-warning {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().transform_error(transform_error);           // expected-warning {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().transform_error(transform_error_void); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
 }
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard2.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard2.verify.cpp
new file mode 100644
index 0000000000000..d3fe1fada2380
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard2.verify.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_NODISCARD_EXPECTED
+
+// <expected>
+
+// Test that ignoring std::expected does not generate [[nodiscard]] warnings.
+
+// expected-no-diagnostics
+
+#include <expected>
+
+std::expected<int, int> returns_expected();
+std::expected<void, int> returns_expected_void();
+
+std::expected<int, int> and_then(int);
+std::expected<void, int> and_then_void();
+std::expected<int, int> or_else(int);
+std::expected<void, int> or_else_void(int);
+int transform(int);
+void transform_void();
+int transform_error(int);
+int transform_error_void(int);
+
+void test() {
+  returns_expected();
+  returns_expected_void();
+
+  returns_expected().and_then(and_then);
+  returns_expected_void().and_then(and_then_void);
+  returns_expected().or_else(or_else);
+  returns_expected_void().or_else(or_else_void);
+  returns_expected().transform(transform);
+  returns_expected_void().transform(transform_void);
+  returns_expected().transform_error(transform_error);
+  returns_expected_void().transform_error(transform_error_void);
+}

>From 795ced59f6547feda202e9ed6b563cc197e18186 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Tue, 13 May 2025 10:34:03 -0400
Subject: [PATCH 4/5] fix clang-format

---
 .../expected.expected/nodiscard.verify.cpp    | 24 ++++++++++++-------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
index 7d2170cbd0554..f795a5f728a47 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
@@ -30,12 +30,20 @@ void test() {
   returns_expected();      // expected-warning {{ignoring return value of type 'expected<int, int>'}}
   returns_expected_void(); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
 
-  returns_expected().and_then(and_then);                         // expected-warning {{ignoring return value of type 'expected<int, int>'}}
-  returns_expected_void().and_then(and_then_void);               // expected-warning {{ignoring return value of type 'expected<void, int>'}}
-  returns_expected().or_else(or_else);                           // expected-warning {{ignoring return value of type 'expected<int, int>'}}
-  returns_expected_void().or_else(or_else_void);                 // expected-warning {{ignoring return value of type 'expected<void, int>'}}
-  returns_expected().transform(transform);                       // expected-warning {{ignoring return value of type 'expected<int, int>'}}
-  returns_expected_void().transform(transform_void);             // expected-warning {{ignoring return value of type 'expected<void, int>'}}
-  returns_expected().transform_error(transform_error);           // expected-warning {{ignoring return value of type 'expected<int, int>'}}
-  returns_expected_void().transform_error(transform_error_void); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().and_then(and_then);
+      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().and_then(and_then_void);
+      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().or_else(or_else);
+      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().or_else(or_else_void);
+      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().transform(transform);
+      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().transform(transform_void);
+      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+  returns_expected().transform_error(transform_error);
+      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+  returns_expected_void().transform_error(transform_error_void);
+      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
 }

>From 2a2761456b6ca15cecd5b6cec4aac64677c477c2 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Sun, 25 May 2025 23:33:23 -0400
Subject: [PATCH 5/5] fix compiling with old compiler

---
 .../expected.expected/nodiscard.verify.cpp       | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
index f795a5f728a47..e9a4183c5394b 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/nodiscard.verify.cpp
@@ -31,19 +31,19 @@ void test() {
   returns_expected_void(); // expected-warning {{ignoring return value of type 'expected<void, int>'}}
 
   returns_expected().and_then(and_then);
-      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected_void().and_then(and_then_void);
-      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected().or_else(or_else);
-      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected_void().or_else(or_else_void);
-      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected().transform(transform);
-      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected_void().transform(transform_void);
-      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected().transform_error(transform_error);
-      // expected-warning at -1 {{ignoring return value of type 'expected<int, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
   returns_expected_void().transform_error(transform_error_void);
-      // expected-warning at -1 {{ignoring return value of type 'expected<void, int>'}}
+      // expected-warning at -1 {{ignoring return value}}
 }



More information about the libcxx-commits mailing list