
Adds explanation why `is_constructible` evaluates to false. This reapplies as-is e476f968bc8e438a0435d10934f148de570db8eb. This was reverted in 16d5db71b3c38f21aa17783a8758f947dca5883f because of a test failure in libc++. The test failure in libc++ is interesting in that, in the absence of nested diagnostics a bunch of diagnostics are emitted as error instead of notes, which we cannot silence with `-verify-ignore-unexpected`. The fix here is to prevent the diagnostics to be emitted in the first place. However this is clearly not ideal and we should make sure to deploy a better solution in the clang 22 time frame, in the lines of https://discourse.llvm.org/t/rfc-add-a-new-text-diagnostics-format-that-supports-nested-diagnostics/87641/12 Fixes #150601 --------- Co-authored-by: Shamshura Egor <164661612+egorshamshura@users.noreply.github.com>
131 lines
6.7 KiB
C++
131 lines
6.7 KiB
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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
|
|
|
// Test the mandates
|
|
// template<class F> constexpr auto and_then(F&& f) &;
|
|
// Mandates:
|
|
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
|
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
|
|
|
// template<class F> constexpr auto and_then(F&& f) const &;
|
|
// Mandates:
|
|
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
|
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
|
|
|
// template<class F> constexpr auto and_then(F&& f) &&;
|
|
// Mandates:
|
|
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
|
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
|
|
|
// template<class F> constexpr auto and_then(F&& f) const &&;
|
|
// Mandates:
|
|
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
|
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
|
|
|
#include <expected>
|
|
#include <utility>
|
|
|
|
struct NotSameAsInt {};
|
|
|
|
int lval_return_not_std_expected(int&) { return 0; }
|
|
int clval_return_not_std_expected(const int&) { return 0; }
|
|
int rval_return_not_std_expected(int&&) { return 0; }
|
|
int crval_return_not_std_expected(const int&&) { return 0; }
|
|
|
|
std::expected<int, NotSameAsInt> lval_error_type_not_same_as_int(int&) { return {}; }
|
|
std::expected<int, NotSameAsInt> clval_error_type_not_same_as_int(const int&) { return {}; }
|
|
std::expected<int, NotSameAsInt> rval_error_type_not_same_as_int(int&&) { return {}; }
|
|
std::expected<int, NotSameAsInt> crval_error_type_not_same_as_int(const int&&) { return {}; }
|
|
|
|
// clang-format off
|
|
void test() {
|
|
// Test & overload
|
|
{
|
|
// 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}}
|
|
// 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{{.*}}}}
|
|
// expected-error@*:* 0-1{{excess elements in struct initializer}}
|
|
}
|
|
|
|
// !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}}
|
|
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must have the same error_type as this expected}}
|
|
}
|
|
}
|
|
|
|
// Test const& overload
|
|
{
|
|
// 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}}
|
|
// 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{{.*}}}}
|
|
// expected-error@*:* 0-1{{excess elements in struct initializer}}
|
|
}
|
|
|
|
// !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}}
|
|
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must have the same error_type as this expected}}
|
|
|
|
}
|
|
}
|
|
|
|
// Test && overload
|
|
{
|
|
// 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}}
|
|
// 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{{.*}}}}
|
|
// expected-error@*:* 0-1{{excess elements in struct initializer}}
|
|
}
|
|
|
|
// !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}}
|
|
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}}
|
|
}
|
|
}
|
|
|
|
// Test const&& overload
|
|
{
|
|
// 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}}
|
|
// 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{{.*}}}}
|
|
// expected-error@*:* 0-1{{excess elements in struct initializer}}
|
|
}
|
|
|
|
// !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}}
|
|
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}}
|
|
}
|
|
}
|
|
}
|
|
// clang-format on
|