Skip to content

Commit a4f73c4

Browse files
committed
Fix broken boost_error_code (#73).
This is actually the first ever time in my life that I had an AI make this entire fix with no involvement from me. I am quite impressed.
1 parent b337c22 commit a4f73c4

File tree

3 files changed

+90
-36
lines changed

3 files changed

+90
-36
lines changed

AGENTS.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Lightweight universal failure handling
2+
3+
## Build instructions
4+
- Use cmake with ninja using the `build` directory
5+
6+
## Test instructions
7+
- Use ctest
8+
9+
## Code style
10+
- Keep code compatible with the C++ 11 standard
11+

include/status-code/boost_error_code.hpp

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class _boost_error_code_domain final : public status_code_domain
7272

7373
std::string _name;
7474

75-
static _base::string_ref _make_string_ref(_error_code_type c) noexcept
75+
static _base::string_ref _make_string_ref(int &errcode, _error_code_type c) noexcept
7676
{
7777
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
7878
try
@@ -84,6 +84,7 @@ class _boost_error_code_domain final : public status_code_domain
8484
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
8585
catch(...)
8686
{
87+
errcode = ENOMEM;
8788
return _base::string_ref("failed to allocate message");
8889
}
8990
#endif
@@ -118,20 +119,24 @@ class _boost_error_code_domain final : public status_code_domain
118119

119120
static inline const _boost_error_code_domain *get(_error_code_type ec);
120121

121-
virtual string_ref name() const noexcept override { return string_ref(_name.c_str(), _name.size()); } // NOLINT
122+
protected:
123+
virtual int _do_name(_vtable_name_args &args) const noexcept override
124+
{
125+
args.ret = string_ref(_name.c_str(), _name.size());
126+
return 0;
127+
} // NOLINT
122128

123-
virtual payload_info_t payload_info() const noexcept override
129+
virtual void _do_payload_info(_vtable_payload_info_args &args) const noexcept override
124130
{
125-
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
126-
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) :
127-
alignof(status_code_domain *)};
131+
args.ret = {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
132+
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) :
133+
alignof(status_code_domain *)};
128134
}
129135

130-
protected:
131136
virtual bool _do_failure(const status_code<void> &code) const noexcept override;
132137
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override;
133-
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override;
134-
virtual string_ref _do_message(const status_code<void> &code) const noexcept override;
138+
virtual void _do_generic_code(_vtable_generic_code_args &args) const noexcept override;
139+
virtual int _do_message(_vtable_message_args &args) const noexcept override;
135140
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(STANDARDESE_IS_IN_THE_HOUSE)
136141
SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override;
137142
#endif
@@ -274,31 +279,34 @@ inline bool _boost_error_code_domain::_do_equivalent(const status_code<void> &co
274279
return false;
275280
}
276281

277-
inline generic_code _boost_error_code_domain::_generic_code(const status_code<void> &code) const noexcept
282+
inline void _boost_error_code_domain::_do_generic_code(_vtable_generic_code_args &args) const noexcept
278283
{
279-
assert(code.domain() == *this);
280-
const auto &c = static_cast<const boost_error_code &>(code); // NOLINT
284+
assert(args.code.domain() == *this);
285+
const auto &c = static_cast<const boost_error_code &>(args.code); // NOLINT
281286
// Ask my embedded error code for its mapping to boost::system::errc, which is a subset of our generic_code errc.
282287
boost::system::error_condition cond(c.category().default_error_condition(c.value()));
283288
if(cond.category() == boost::system::generic_category())
284289
{
285-
return generic_code(static_cast<errc>(cond.value()));
290+
args.ret = generic_code(static_cast<errc>(cond.value()));
291+
return;
286292
}
287293
#if !defined(SYSTEM_ERROR2_NOT_POSIX) && !defined(_WIN32)
288294
if(cond.category() == boost::system::system_category())
289295
{
290-
return generic_code(static_cast<errc>(cond.value()));
296+
args.ret = generic_code(static_cast<errc>(cond.value()));
297+
return;
291298
}
292299
#endif
293-
return errc::unknown;
300+
args.ret = errc::unknown;
294301
}
295302

296-
inline _boost_error_code_domain::string_ref
297-
_boost_error_code_domain::_do_message(const status_code<void> &code) const noexcept
303+
inline int _boost_error_code_domain::_do_message(_vtable_message_args &args) const noexcept
298304
{
299-
assert(code.domain() == *this);
300-
const auto &c = static_cast<const boost_error_code &>(code); // NOLINT
301-
return _make_string_ref(_error_code_type(c.value(), c.category()));
305+
assert(args.code.domain() == *this);
306+
const auto &c = static_cast<const boost_error_code &>(args.code); // NOLINT
307+
int ret = 0;
308+
args.ret = _make_string_ref(ret, _error_code_type(c.value(), c.category()));
309+
return ret;
302310
}
303311

304312
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(STANDARDESE_IS_IN_THE_HOUSE)

test/main.cpp

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ Distributed under the Boost Software License, Version 1.0.
3737
#include "status-code/system_code_from_exception.hpp"
3838
#endif
3939

40+
#if __has_include(<boost/system.hpp>)
41+
#include "status-code/boost_error_code.hpp"
42+
#define TEST_BOOST_SYSTEM_CODE 1
43+
#endif
44+
4045
#include <cstdio>
4146
#include <cstring> // for strdup, strlen
4247
#include <iostream>
@@ -705,27 +710,57 @@ int main()
705710
#endif
706711

707712
// Test std_error_code
708-
std::error_code error_codes[] = {make_error_code(std::errc::permission_denied), {ERANGE, std::generic_category()}};
709-
printf("\n");
710-
for(size_t n = 0; n < sizeof(error_codes) / sizeof(error_codes[0]); n++)
711713
{
712-
std_error_code ec(error_codes[n]);
713-
printf("error_code[%zu] has domain %s value (%s) and errc::permission_denied == error = %d\n", n,
714-
ec.domain().name().c_str(), ec.message().c_str(), static_cast<int>(errc::permission_denied == ec));
715-
CHECK(n != 0 || ec == errc::permission_denied);
714+
std::error_code error_codes[] = {make_error_code(std::errc::permission_denied), {ERANGE, std::generic_category()}};
715+
printf("\n");
716+
for(size_t n = 0; n < sizeof(error_codes) / sizeof(error_codes[0]); n++)
717+
{
718+
std_error_code ec(error_codes[n]);
719+
printf("error_code[%zu] has domain %s value (%s) and errc::permission_denied == error = %d\n", n,
720+
ec.domain().name().c_str(), ec.message().c_str(), static_cast<int>(errc::permission_denied == ec));
721+
CHECK(n != 0 || ec == errc::permission_denied);
722+
}
723+
system_code ec1(error_codes[0]), ec2(error_codes[1]);
724+
CHECK(ec1 == errc::permission_denied);
725+
CHECK(ec2 == errc::result_out_of_range);
726+
{
727+
struct error_info
728+
{
729+
system_code::value_type _system_code;
730+
char bytes[16];
731+
};
732+
static_assert(std::is_constructible<erased_status_code<error_info>, std::error_code>::value,
733+
"An erased status code is not constructible from a std::error_code");
734+
}
716735
}
717-
system_code ec1(error_codes[0]), ec2(error_codes[1]);
718-
CHECK(ec1 == errc::permission_denied);
719-
CHECK(ec2 == errc::result_out_of_range);
736+
737+
#ifdef TEST_BOOST_SYSTEM_CODE
738+
// Test boost_error_code
720739
{
721-
struct error_info
740+
boost::system::error_code error_codes[] = {make_error_code(boost::system::errc::permission_denied),
741+
{ERANGE, boost::system::generic_category()}};
742+
printf("\n");
743+
for(size_t n = 0; n < sizeof(error_codes) / sizeof(error_codes[0]); n++)
722744
{
723-
system_code::value_type _system_code;
724-
char bytes[16];
725-
};
726-
static_assert(std::is_constructible<erased_status_code<error_info>, std::error_code>::value,
727-
"An erased status code is not constructible from a std::error_code");
745+
boost_error_code ec(error_codes[n]);
746+
printf("error_code[%zu] has domain %s value (%s) and errc::permission_denied == error = %d\n", n,
747+
ec.domain().name().c_str(), ec.message().c_str(), static_cast<int>(errc::permission_denied == ec));
748+
CHECK(n != 0 || ec == errc::permission_denied);
749+
}
750+
system_code ec1(error_codes[0]), ec2(error_codes[1]);
751+
CHECK(ec1 == errc::permission_denied);
752+
CHECK(ec2 == errc::result_out_of_range);
753+
{
754+
struct error_info
755+
{
756+
system_code::value_type _system_code;
757+
char bytes[16];
758+
};
759+
static_assert(std::is_constructible<erased_status_code<error_info>, boost::system::error_code>::value,
760+
"An erased status code is not constructible from a boost::system::error_code");
761+
}
728762
}
763+
#endif
729764

730765
#ifndef SYSTEM_ERROR2_NOT_POSIX
731766
// Test nested_status_code

0 commit comments

Comments
 (0)