Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions libcxx/docs/UserDocumentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__expected/expected.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ class __expected_base {
};

template <class _Tp, class _Err>
class 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,
Expand Down Expand Up @@ -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 _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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand All @@ -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{{.*}}}}
Expand All @@ -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}}

}
Expand All @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand All @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
//
// 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();

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@-1 {{ignoring return value}}
returns_expected_void().and_then(and_then_void);
// expected-warning@-1 {{ignoring return value}}
returns_expected().or_else(or_else);
// expected-warning@-1 {{ignoring return value}}
returns_expected_void().or_else(or_else_void);
// expected-warning@-1 {{ignoring return value}}
returns_expected().transform(transform);
// expected-warning@-1 {{ignoring return value}}
returns_expected_void().transform(transform_void);
// expected-warning@-1 {{ignoring return value}}
returns_expected().transform_error(transform_error);
// expected-warning@-1 {{ignoring return value}}
returns_expected_void().transform_error(transform_error_void);
// expected-warning@-1 {{ignoring return value}}
}
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand All @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand All @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand All @@ -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{{.*}}}}
Expand All @@ -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}}
}
}
Expand Down
Loading
Loading