#include <fmt/format.h>
using EH = fmt::detail::error_handler;
namespace fmt::detail {
template <typename Char, typename ErrorHandler = detail::error_handler>
class CompileParseContext
: public basic_format_parse_context<Char, ErrorHandler> {
private:
int num_args_;
const type* types_;
using base = basic_format_parse_context<Char, ErrorHandler>;
public:
explicit constexpr CompileParseContext(
basic_string_view<Char> format_str, int num_args, const type* types,
ErrorHandler eh = {}, int next_arg_id = 0)
: base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {}
};
}
struct FormatStringChecker {
#ifdef OK
using parse_context_type = fmt::detail::CompileParseContext<char, EH>;
#else
using parse_context_type = fmt::detail::compile_parse_context<char, EH>;
#endif
parse_context_type context_;
fmt::detail::type types_[1];
constexpr FormatStringChecker(fmt::string_view format_str, EH eh)
: context_(format_str, 0, types_, eh)
, types_{}
{ }
};
void show() {
FormatStringChecker c("", {});
}
When I run (with clang-15 and fmt-9.1.0):
$ clang-tidy -checks='-*,clang-analyzer-optin.cplusplus.UninitializedObject' foo.cxx -- -std=c++17 -I fmt/include -DOK
$ clang-tidy -checks='-*,clang-analyzer-optin.cplusplus.UninitializedObject' foo.cxx -- -std=c++17 -I fmt/include
1 warning generated.
/home/brevzin/sandbox/foo.cxx:34:17: error: 5 uninitialized fields at the end of the constructor call [clang-analyzer-optin.cplusplus.UninitializedObject,-warnings-as-errors]
, types_{}
^
/home/brevzin/sandbox/fmt/include/fmt/core.h:732:7: note: uninitialized field 'this->context_.num_args_'
int num_args_;
^~~~~~~~~
/home/brevzin/sandbox/fmt/include/fmt/core.h:733:15: note: uninitialized pointer 'this->context_.types_'
const type* types_;
^~~~~~
/home/brevzin/sandbox/fmt/include/fmt/core.h:432:15: note: uninitialized pointer 'this->context_.basic_format_parse_context::format_str_.data_'
const Char* data_;
^~~~~
/home/brevzin/sandbox/fmt/include/fmt/core.h:433:10: note: uninitialized field 'this->context_.basic_format_parse_context::format_str_.size_'
size_t size_;
^~~~~
/home/brevzin/sandbox/fmt/include/fmt/core.h:657:7: note: uninitialized field 'this->context_.basic_format_parse_context::next_arg_id_'
int next_arg_id_;
^~~~~~~~~~~~
/home/brevzin/sandbox/foo.cxx:39:25: note: Calling constructor for 'FormatStringChecker'
FormatStringChecker c("", {});
^~~~~~~~~
/home/brevzin/sandbox/foo.cxx:34:17: note: 5 uninitialized fields at the end of the constructor call
, types_{}
^~
1 warning treated as error
All of these fields are actually initialized though. What's especially confusing is that my CompileParseContext is exactly the same as fmt::detail::compile_parse_context, as you can see here:
template <typename Char, typename ErrorHandler = detail::error_handler>
class compile_parse_context
: public basic_format_parse_context<Char, ErrorHandler> {
private:
int num_args_;
const type* types_;
using base = basic_format_parse_context<Char, ErrorHandler>;
public:
explicit FMT_CONSTEXPR compile_parse_context(
basic_string_view<Char> format_str, int num_args, const type* types,
ErrorHandler eh = {}, int next_arg_id = 0)
: base(format_str, eh, next_arg_id), num_args_(num_args), types_(types) {}
And yet my version (which I copied to continue attempting to reduce) doesn't give uninitialized errors.
Trying to reduce this from some fmt code:
When I run (with clang-15 and fmt-9.1.0):
All of these fields are actually initialized though. What's especially confusing is that my
CompileParseContext
is exactly the same asfmt::detail::compile_parse_context
, as you can see here:And yet my version (which I copied to continue attempting to reduce) doesn't give uninitialized errors.