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

tinyformat: Add compile-time checking for literal format strings #31174

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
tinyformat: Add compile-time checking for literal format strings
Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^[email protected]>
  • Loading branch information
ryanofsky and MarcoFalke committed Oct 28, 2024
commit fe39acf88ff552bfc4a502c99774375b91824bb1
30 changes: 17 additions & 13 deletions src/tinyformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ namespace tfm = tinyformat;
#include <iostream>
#include <sstream>
#include <stdexcept> // Added for Bitcoin Core
#include <util/string.h> // Added for Bitcoin Core

#ifndef TINYFORMAT_ASSERT
# include <cassert>
Expand Down Expand Up @@ -178,6 +179,18 @@ namespace tfm = tinyformat;

namespace tinyformat {

// Added for Bitcoin Core. Wrapper for checking format strings at compile time.
// Unlike ConstevalFormatString this supports std::string for runtime string
// formatting without compile time checks.
template <unsigned num_params>
struct FormatStringCheck {
Copy link
Contributor

Choose a reason for hiding this comment

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

Checked and failures seem to be validated successfully from command line, but - unlike the previous versions - doesn't seem to be shown in the IDE... Weird :/

consteval FormatStringCheck(const char* str) : fmt{util::ConstevalFormatString<num_params>{str}.fmt} {}
FormatStringCheck(const std::string& str) : fmt{str.c_str()} {}
FormatStringCheck(util::ConstevalFormatString<num_params> str) : fmt{str.fmt} {}
operator const char*() { return fmt; }
const char* fmt;
};

// Added for Bitcoin Core
class format_error: public std::runtime_error
{
Expand Down Expand Up @@ -1056,15 +1069,15 @@ inline void vformat(std::ostream& out, const char* fmt, FormatListRef list)

/// Format list of arguments to the stream according to given format string.
template<typename... Args>
void format(std::ostream& out, const char* fmt, const Args&... args)
void format(std::ostream& out, FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{
vformat(out, fmt, makeFormatList(args...));
}

/// Format list of arguments according to the given format string and return
/// the result as a string.
template<typename... Args>
std::string format(const char* fmt, const Args&... args)
std::string format(FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
ryanofsky marked this conversation as resolved.
Show resolved Hide resolved
{
std::ostringstream oss;
format(oss, fmt, args...);
Expand All @@ -1073,13 +1086,13 @@ std::string format(const char* fmt, const Args&... args)

/// Format list of arguments to std::cout, according to the given format string
template<typename... Args>
void printf(const char* fmt, const Args&... args)
void printf(FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{
format(std::cout, fmt, args...);
}

template<typename... Args>
void printfln(const char* fmt, const Args&... args)
void printfln(FormatStringCheck<sizeof...(Args)> fmt, const Args&... args)
{
format(std::cout, fmt, args...);
std::cout << '\n';
Expand Down Expand Up @@ -1145,15 +1158,6 @@ TINYFORMAT_FOREACH_ARGNUM(TINYFORMAT_MAKE_FORMAT_FUNCS)

#endif

// Added for Bitcoin Core
template<typename... Args>
std::string format(const std::string &fmt, const Args&... args)
{
std::ostringstream oss;
format(oss, fmt.c_str(), args...);
return oss.str();
}

} // namespace tinyformat

// Added for Bitcoin Core:
Expand Down
9 changes: 0 additions & 9 deletions src/util/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#define BITCOIN_UTIL_STRING_H

#include <span.h>
#include <tinyformat.h>

#include <array>
#include <cstdint>
Expand Down Expand Up @@ -247,12 +246,4 @@ template <typename T1, size_t PREFIX_LEN>
}
} // namespace util

namespace tinyformat {
template <typename... Args>
std::string format(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
{
return format(fmt.fmt, args...);
}
} // namespace tinyformat

#endif // BITCOIN_UTIL_STRING_H
Loading