CWG 2631 (https://cplusplus.github.io/CWG/issues/2631.html) reports
an issue on how the default argument is evaluated. this problem is
more obvious when it comes to how `std::source_location::current()`
is evaluated as a default argument. but not all compilers have the
same behavior, see https://godbolt.org/z/PK865KdG4.
notebaly, clang-15 evaluates the default argument at the callee
site. so we need to check the capability of compiler and fall back
to the one defined by util/source_location-compat.hh if the compiler
suffers from CWG 2631. and clang-16 implemented CWG2631 in
https://reviews.llvm.org/D136554. But unfortunately, this change
was not backported to clang-15.
before switching over to clang-16, for using std::source_location::current()
as the default parameter and expect the behavior defined by CWG2631,
we have to use the compatible layer provided by Seastar. otherwise
we always end up having the source_location at the callee side, which
is not interesting under most circumstances.
so in this change, all places using the idiom of passing
std::source_location::current() as the default parameter are changed
to use seastar::compat::source_location::current(). despite that
we have `#include "seastarx.h"` for opening the seastar namespace,
to disambiguate the "namespace compat" defined somewhere in scylladb,
the fully qualified name of
`seastar::compat::source_location::current()` is used.
see also 09a3c63345, where we used
std::source_location as an alias of std::experimental::source_location
if it was available. but this does not apply to the settings of our
current toolchain, where we have GCC-12 and Clang-15.
Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
Closes #14086
56 lines
2.3 KiB
C++
56 lines
2.3 KiB
C++
/*
|
|
* Copyright (C) 2019-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#include "test/lib/exception_utils.hh"
|
|
|
|
#include <boost/regex.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <fmt/format.h>
|
|
#include <fmt/ostream.h>
|
|
|
|
std::function<bool(const std::exception&)> exception_predicate::make(
|
|
std::function<bool(const std::exception&)> check,
|
|
std::function<sstring(const std::exception&)> err) {
|
|
return [check = std::move(check), err = std::move(err)] (const std::exception& e) {
|
|
const bool status = check(e);
|
|
BOOST_CHECK_MESSAGE(status, err(e));
|
|
return status;
|
|
};
|
|
}
|
|
|
|
std::function<bool(const std::exception&)> exception_predicate::message_contains(
|
|
const sstring& fragment,
|
|
const seastar::compat::source_location& loc) {
|
|
return make([=] (const std::exception& e) { return sstring(e.what()).find(fragment) != sstring::npos; },
|
|
[=] (const std::exception& e) {
|
|
return fmt::format("Message '{}' doesn't contain '{}'\n{}:{}: invoked here",
|
|
e.what(), fragment, loc.file_name(), loc.line());
|
|
});
|
|
}
|
|
|
|
std::function<bool(const std::exception&)> exception_predicate::message_equals(
|
|
const sstring& text,
|
|
const seastar::compat::source_location& loc) {
|
|
return make([=] (const std::exception& e) { return text == e.what(); },
|
|
[=] (const std::exception& e) {
|
|
return fmt::format("Message '{}' doesn't equal '{}'\n{}:{}: invoked here",
|
|
e.what(), text, loc.file_name(), loc.line());
|
|
});
|
|
}
|
|
|
|
std::function<bool(const std::exception&)> exception_predicate::message_matches(
|
|
const std::string& regex,
|
|
const seastar::compat::source_location& loc) {
|
|
// Use boost::regex since std::regex (with libstdc++ 12) uses too much stack
|
|
return make([=] (const std::exception& e) { return boost::regex_search(e.what(), boost::regex(regex)); },
|
|
[=] (const std::exception& e) {
|
|
return fmt::format("Message '{}' doesn't match '{}'\n{}:{}: invoked here",
|
|
e.what(), regex, loc.file_name(), loc.line());
|
|
});
|
|
}
|