diff --git a/lib/boost_format_compat.h b/lib/boost_format_compat.h new file mode 100644 index 0000000000..c53f92fa8e --- /dev/null +++ b/lib/boost_format_compat.h @@ -0,0 +1,41 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef LIB_BOOST_FORMAT_COMPAT_H_ +#define LIB_BOOST_FORMAT_COMPAT_H_ + +#include + +namespace P4 { + +/// Allocator wrapper that adds the overload removed in C++20 for the sake of Boost. +template +struct BoostCompatAllocator : std::allocator { + /// make sure the base class'es allocate is visible. + using std::allocator::allocate; + + /// This one was removed in C++20, but boost::format < 1.74 needs it. + T *allocate(typename std::allocator::size_type n, const void *) { return allocate(n); } +}; + +/// Boost < 1.74 is not compatible with C++20 as it expect deprecated +/// allocator::allocate(size_type, void*) to exist. To work around that, we use a simple wrapper +/// over std::allocator that adds this overload back. All uses of boost::format in P4C should use +// this type instead. +using BoostFormatCompat = + boost::basic_format, BoostCompatAllocator>; + +} // namespace P4 + +#endif // LIB_BOOST_FORMAT_COMPAT_H_ diff --git a/lib/bug_helper.h b/lib/bug_helper.h index c8f52eec75..bd2cdee3b4 100644 --- a/lib/bug_helper.h +++ b/lib/bug_helper.h @@ -23,9 +23,8 @@ limitations under the License. #include #include -#include - #include "absl/strings/str_cat.h" +#include "boost_format_compat.h" #include "cstring.h" #include "source_file.h" #include "stringify.h" @@ -60,27 +59,27 @@ std::pair maybeAddSourceInfo(const T &t, std::str return {"", ""}; } -static inline std::string bug_helper(boost::format &f, std::string_view position, +static inline std::string bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail) { return absl::StrCat(position, position.empty() ? "" : ": ", boost::str(f), "\n", tail); } template -auto bug_helper(boost::format &f, std::string_view position, std::string_view tail, const T *t, +auto bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, const T *t, Args &&...args); template -auto bug_helper(boost::format &f, std::string_view position, std::string_view tail, const T &t, +auto bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, const T &t, Args &&...args) -> std::enable_if_t, std::string>; template -std::string bug_helper(boost::format &f, std::string_view position, std::string_view tail, +std::string bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, const char *t, Args &&...args) { return bug_helper(f % t, position, tail, std::forward(args)...); } template -std::string bug_helper(boost::format &f, std::string_view position, std::string_view tail, +std::string bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, const Util::SourceInfo &info, Args &&...args) { auto [outPos, outTail] = detail::getPositionTail(info, position, tail); return bug_helper(f % "", outPos, outTail, std::forward(args)...); @@ -105,7 +104,7 @@ std::ostream &operator<<(std::ostream &os, const DbprintDispatchPtr &dispatch } template -auto bug_helper(boost::format &f, std::string_view position, std::string_view tail, const T *t, +auto bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, const T *t, Args &&...args) { if (t == nullptr) return bug_helper(f, position, tail, std::forward(args)...); @@ -132,7 +131,7 @@ std::ostream &operator<<(std::ostream &os, const DbprintDispatchRef &dispatch } template -auto bug_helper(boost::format &f, std::string_view position, std::string_view tail, const T &t, +auto bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, const T &t, Args &&...args) -> std::enable_if_t, std::string> { auto [outPos, outTail] = maybeAddSourceInfo(t, position, tail); return bug_helper(f % DbprintDispatchRef{t}, outPos, outTail, std::forward(args)...); @@ -141,7 +140,7 @@ auto bug_helper(boost::format &f, std::string_view position, std::string_view ta // Most direct invocations of bug_helper usually only reduce arguments template -std::string bug_helper(boost::format &f, std::string_view position, std::string_view tail, +std::string bug_helper(BoostFormatCompat &f, std::string_view position, std::string_view tail, Args &&...args) { return detail::bug_helper(f, position, tail, std::forward(args)...); } diff --git a/lib/error_helper.h b/lib/error_helper.h index bedf17f09e..081f6269a0 100644 --- a/lib/error_helper.h +++ b/lib/error_helper.h @@ -16,9 +16,9 @@ limitations under the License. #ifndef LIB_ERROR_HELPER_H_ #define LIB_ERROR_HELPER_H_ -#include +#include -#include +#include #include "lib/error_message.h" #include "lib/source_file.h" @@ -29,26 +29,26 @@ namespace priv { // All these methods return std::string because this is the native format of boost::format // Position is printed at the beginning. -static inline ErrorMessage error_helper(boost::format &f, ErrorMessage out) { +static inline ErrorMessage error_helper(BoostFormatCompat &f, ErrorMessage out) { out.message = boost::str(f); return out; } template -auto error_helper(boost::format &f, ErrorMessage out, const char *t, Args &&...args) { +auto error_helper(BoostFormatCompat &f, ErrorMessage out, const char *t, Args &&...args) { return error_helper(f % t, out, std::forward(args)...); } template -auto error_helper(boost::format &f, ErrorMessage out, const T &t, - Args &&...args) -> std::enable_if_t, ErrorMessage>; +auto error_helper(BoostFormatCompat &f, ErrorMessage out, const T &t, Args &&...args) + -> std::enable_if_t, ErrorMessage>; template -auto error_helper(boost::format &f, ErrorMessage out, const T &t, Args &&...args) +auto error_helper(BoostFormatCompat &f, ErrorMessage out, const T &t, Args &&...args) -> std::enable_if_t && !std::is_pointer_v, ErrorMessage>; template -auto error_helper(boost::format &f, ErrorMessage out, const T *t, Args &&...args) { +auto error_helper(BoostFormatCompat &f, ErrorMessage out, const T *t, Args &&...args) { // Contrary to bug_helper we do not want to show raw pointers to users in // ordinary error messages. Therefore we explicitly delegate to // reference-arg implementation here. @@ -56,7 +56,7 @@ auto error_helper(boost::format &f, ErrorMessage out, const T *t, Args &&...args } template -ErrorMessage error_helper(boost::format &f, ErrorMessage out, const Util::SourceInfo &info, +ErrorMessage error_helper(BoostFormatCompat &f, ErrorMessage out, const Util::SourceInfo &info, Args &&...args) { if (info.isValid()) out.locations.push_back(info); return error_helper(f % "", std::move(out), std::forward(args)...); @@ -71,15 +71,15 @@ void maybeAddSourceInfo(ErrorMessage &out, const T &t) { } template -auto error_helper(boost::format &f, ErrorMessage out, const T &t, Args &&...args) +auto error_helper(BoostFormatCompat &f, ErrorMessage out, const T &t, Args &&...args) -> std::enable_if_t && !std::is_pointer_v, ErrorMessage> { maybeAddSourceInfo(out, t); return error_helper(f % t, std::move(out), std::forward(args)...); } template -auto error_helper(boost::format &f, ErrorMessage out, const T &t, - Args &&...args) -> std::enable_if_t, ErrorMessage> { +auto error_helper(BoostFormatCompat &f, ErrorMessage out, const T &t, Args &&...args) + -> std::enable_if_t, ErrorMessage> { maybeAddSourceInfo(out, t); return error_helper(f % t.toString(), std::move(out), std::forward(args)...); } @@ -88,21 +88,21 @@ auto error_helper(boost::format &f, ErrorMessage out, const T &t, // Most direct invocations of error_helper usually only reduce arguments template -ErrorMessage error_helper(boost::format &f, Args &&...args) { +ErrorMessage error_helper(BoostFormatCompat &f, Args &&...args) { ErrorMessage msg; return priv::error_helper(f, msg, std::forward(args)...); } // Invoked from ErrorReporter template -ErrorMessage error_helper(boost::format &f, ErrorMessage msg, Args &&...args) { +ErrorMessage error_helper(BoostFormatCompat &f, ErrorMessage msg, Args &&...args) { return priv::error_helper(f, std::move(msg), std::forward(args)...); } // This overload exists for backwards compatibility template -ErrorMessage error_helper(boost::format &f, const std::string &prefix, const Util::SourceInfo &info, - const std::string &suffix, Args &&...args) { +ErrorMessage error_helper(BoostFormatCompat &f, const std::string &prefix, + const Util::SourceInfo &info, const std::string &suffix, Args &&...args) { return priv::error_helper(f, ErrorMessage(prefix, info, suffix), std::forward(args)...); } diff --git a/lib/error_reporter.h b/lib/error_reporter.h index b0005c4b8c..9b8962ea0d 100644 --- a/lib/error_reporter.h +++ b/lib/error_reporter.h @@ -23,9 +23,8 @@ limitations under the License. #include #include -#include - #include "absl/strings/str_format.h" +#include "boost_format_compat.h" #include "bug_helper.h" #include "error_catalog.h" #include "error_helper.h" @@ -96,7 +95,7 @@ class ErrorReporter { // error message for a bug template std::string bug_message(const char *format, Args &&...args) { - boost::format fmt(format); + BoostFormatCompat fmt(format); // FIXME: This will implicitly take location of the first argument having // SourceInfo. Not sure if this always desireable or not. return ::P4::bug_helper(fmt, "", "", std::forward(args)...); @@ -104,7 +103,7 @@ class ErrorReporter { template std::string format_message(const char *format, Args &&...args) { - boost::format fmt(format); + BoostFormatCompat fmt(format); return ::P4::error_helper(fmt, std::forward(args)...).toString(); } @@ -157,7 +156,7 @@ class ErrorReporter { msgType = ErrorMessage::MessageType::Error; } - boost::format fmt(format); + BoostFormatCompat fmt(format); ErrorMessage msg(msgType, diagnosticName ? diagnosticName : "", suffix); msg = ::P4::error_helper(fmt, msg, std::forward(args)...); emit_message(msg); diff --git a/lib/exceptions.h b/lib/exceptions.h index 0f62fde093..fc59df0a1e 100644 --- a/lib/exceptions.h +++ b/lib/exceptions.h @@ -76,7 +76,7 @@ class P4CExceptionBase : public std::exception { template explicit P4CExceptionBase(const char *format, Args &&...args) { traceCreation(); - boost::format fmt(format); + BoostFormatCompat fmt(format); // FIXME: This will implicitly take location of the first argument having // SourceInfo. Not sure if this always desireable or not. message = ::P4::bug_helper(fmt, "", "", std::forward(args)...);