Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement LWG-3629 make_error_code and make_error_condition are customization points #3272

Merged
merged 5 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 4 additions & 4 deletions stl/inc/future
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ public:
void _Abandon() { // abandon shared state
unique_lock<mutex> _Lock(_Mtx);
if (!_Already_has_stored_result()) { // queue exception
future_error _Fut(make_error_code(future_errc::broken_promise));
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_Set_exception_raw(_STD make_exception_ptr(_Fut), &_Lock, false);
}
}
Expand Down Expand Up @@ -1180,7 +1180,7 @@ public:
~promise() noexcept {
if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit()) {
// exception if destroyed before function object returns
future_error _Fut(make_error_code(future_errc::broken_promise));
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
}
}
Expand Down Expand Up @@ -1242,7 +1242,7 @@ public:
~promise() noexcept {
if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit()) {
// exception if destroyed before function object returns
future_error _Fut(make_error_code(future_errc::broken_promise));
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
}
}
Expand Down Expand Up @@ -1296,7 +1296,7 @@ public:
~promise() noexcept {
if (_MyPromise._Is_valid() && !_MyPromise._Is_ready() && !_MyPromise._Is_ready_at_thread_exit()) {
// exception if destroyed before function object returns
future_error _Fut(make_error_code(future_errc::broken_promise));
future_error _Fut(_STD make_error_code(future_errc::broken_promise));
_MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
}
}
Expand Down
13 changes: 9 additions & 4 deletions stl/inc/system_error
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ _INLINE_VAR constexpr bool is_error_condition_enum_v = is_error_condition_enum<_

_EXPORT_STD class error_code;
_EXPORT_STD class error_condition;
_EXPORT_STD _NODISCARD error_code make_error_code(errc) noexcept;
_EXPORT_STD _NODISCARD error_code make_error_code(io_errc) noexcept;
_EXPORT_STD _NODISCARD error_condition make_error_condition(errc) noexcept;
_EXPORT_STD _NODISCARD error_condition make_error_condition(io_errc) noexcept;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

namespace _Ensure_adl {
void make_error_code() = delete;
void make_error_condition() = delete;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For other reviewers: this change doesn't need to workaround the MSVC bug that was an issue for the CPOs (#3215 (comment)), that bug only affects names in requires-expressions. (No change requested.)

} // namespace _Ensure_adl

_EXPORT_STD class error_category;

Expand Down Expand Up @@ -168,6 +169,7 @@ public:

template <class _Enum, enable_if_t<is_error_code_enum_v<_Enum>, int> = 0>
error_code(_Enum _Errcode) noexcept : _Myval(0), _Mycat(nullptr) {
using _Ensure_adl::make_error_code;
*this = make_error_code(_Errcode); // using ADL
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}

Expand All @@ -178,6 +180,7 @@ public:

template <class _Enum, enable_if_t<is_error_code_enum_v<_Enum>, int> = 0>
error_code& operator=(_Enum _Errcode) noexcept {
using _Ensure_adl::make_error_code;
*this = make_error_code(_Errcode); // using ADL
return *this;
}
Expand Down Expand Up @@ -259,6 +262,7 @@ public:

template <class _Enum, enable_if_t<is_error_condition_enum_v<_Enum>, int> = 0>
error_condition(_Enum _Errcode) noexcept : _Myval(0), _Mycat(nullptr) {
using _Ensure_adl::make_error_condition;
*this = make_error_condition(_Errcode); // using ADL
}

Expand All @@ -269,6 +273,7 @@ public:

template <class _Enum, enable_if_t<is_error_condition_enum_v<_Enum>, int> = 0>
error_condition& operator=(_Enum _Errcode) noexcept {
using _Ensure_adl::make_error_condition;
*this = make_error_condition(_Errcode); // using ADL
return *this;
}
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/xiosbase
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ public:

class failure : public system_error { // base of all iostreams exceptions
public:
explicit failure(const string& _Message, const error_code& _Errcode = make_error_code(io_errc::stream))
explicit failure(const string& _Message, const error_code& _Errcode = _STD make_error_code(io_errc::stream))
: system_error(_Errcode, _Message) {} // construct with message

explicit failure(const char* _Message, const error_code& _Errcode = make_error_code(io_errc::stream))
explicit failure(const char* _Message, const error_code& _Errcode = _STD make_error_code(io_errc::stream))
: system_error(_Errcode, _Message) {} // construct with message

#if !_HAS_EXCEPTIONS
Expand Down
77 changes: 77 additions & 0 deletions tests/std/tests/Dev11_0493504_error_category_lifetime/test.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// Intentionally declare variables of these names before the inclusion of standard headers. See LWG-3629.
struct InvalidFunctor {
template <class T>
void operator()(T&&) const = delete;
};

InvalidFunctor make_error_code{};
InvalidFunctor make_error_condition{};

#include <cassert>
#include <cctype>
#include <ios>
#include <system_error>
#include <type_traits>

#ifndef _M_CEE_PURE
#include <future>
Expand Down Expand Up @@ -41,6 +51,9 @@ void test_lwg_3598() {

// Also test GH-2572: WAIT_TIMEOUT is not matched against by std::errc::timed_out
void test_gh_2572() {
using std::make_error_code;
using std::make_error_condition;

assert((errc::timed_out == error_code{WAIT_TIMEOUT, system_category()}));
assert((make_error_condition(errc::timed_out) == error_code{WAIT_TIMEOUT, system_category()}));

Expand All @@ -53,6 +66,9 @@ void test_gh_2572() {

// Also test GH-2893 <system_error>: Several Windows system errors are not mapped
void test_gh_2893() {
using std::make_error_code;
using std::make_error_condition;

assert((errc::filename_too_long == error_code{ERROR_FILENAME_EXCED_RANGE, system_category()}));
assert(
(make_error_condition(errc::filename_too_long) == error_code{ERROR_FILENAME_EXCED_RANGE, system_category()}));
Expand All @@ -62,7 +78,67 @@ void test_gh_2893() {
(make_error_condition(errc::no_such_file_or_directory) == error_code{ERROR_BAD_NET_NAME, system_category()}));
}

// Also test LWG-3629 make_error_code and make_error_condition are customization points
namespace test_ns {
struct friendly_error {
friend error_code make_error_code(friendly_error) {
return error_code{};
}

friend error_condition make_error_condition(friendly_error) {
return error_condition{};
}
};

struct converted_errc : enable_if<false> {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
operator errc() const {
return errc{};
}
};

struct converted_io_errc : enable_if<false> {
operator io_errc() const {
return io_errc{};
}
};
} // namespace test_ns

template <>
struct is_error_code_enum<test_ns::friendly_error> : true_type {};

template <>
struct is_error_code_enum<test_ns::converted_io_errc> : true_type {};

template <>
struct is_error_condition_enum<test_ns::friendly_error> : true_type {};

template <>
struct is_error_condition_enum<test_ns::converted_errc> : true_type {};

void test_lwg_3629() {
#ifndef _M_CEE_PURE
error_code err_future{future_errc{}};
(void) err_future;
#endif // _M_CEE_PURE
error_code err_io{io_errc{}};
(void) err_io;
error_condition errcond{errc{}};
(void) errcond;

error_code ec_friendly{test_ns::friendly_error{}};
(void) ec_friendly;
error_code ec_converted_io{test_ns::converted_io_errc{}};
(void) ec_converted_io;
error_condition econd_friendly{test_ns::friendly_error{}};
(void) econd_friendly;
error_condition econd_converted{test_ns::converted_errc{}};
(void) econd_converted;
}

int main() {
using std::make_error_code;
using std::make_error_condition;

// Also test DevDiv-781294 "<system_error>: Visual C++ 2013 RC system_category().equivalent function does not work".
const error_code code(ERROR_NOT_ENOUGH_MEMORY, system_category());

Expand All @@ -80,6 +156,7 @@ int main() {
assert(!msg.empty() && msg.back() != '\0' && !isspace(static_cast<unsigned char>(msg.back())));

test_lwg_3598();
test_lwg_3629();

test_gh_2572();
test_gh_2893();
Expand Down