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

Static Assert failure with intel-19 #2746

Closed
gsjaardema opened this issue Feb 8, 2022 · 23 comments
Closed

Static Assert failure with intel-19 #2746

gsjaardema opened this issue Feb 8, 2022 · 23 comments

Comments

@gsjaardema
Copy link
Contributor

There seems to be an issue with the intel-19 c++ compiler and the use of fmt::group_digits(). A simple reproducer is below:

>>> cat test-1.C
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <string>
#include <sstream>

int main()
{
  std::ostringstream errmsg;
  int age = 56;
  fmt::print(errmsg, "I am {} years old\n", fmt::group_digits(age));
}

I try to compile:

>>>> icpc -I../fmt_copy test-1.C
../fmt_copy/fmt/core.h(1706): error: static assertion failed with "Cannot format a const argument."
    static_assert(formattable_const, "Cannot format a const argument.");
    ^
          detected during:
            instantiation of "auto fmt::v8::detail::make_arg<IS_PACKED,Context,<unnamed>,T,<unnamed>>(T &&)->fmt::v8::detail::value<Context> [with IS_PACKED=true, Context=fmt::v8::basic_format_context<fmt::v8::detail::buffer_appender<char>, char>, <unnamed>=fmt::v8::detail::type::custom_type, T=const fmt::v8::remove_cvref_t<const fmt::v8::remove_reference_t<fmt::v8::group_digits_view<int>> &> &, <unnamed>=0]" at line 1848
            instantiation of "fmt::v8::format_arg_store<Context, Args...>::format_arg_store(T &&...) [with Context=fmt::v8::basic_format_context<fmt::v8::detail::buffer_appender<char>, char>, Args=<fmt::v8::group_digits_view<int>>, T=<const fmt::v8::remove_reference_t<fmt::v8::group_digits_view<int>> &>]" at line 850 of "../fmt_copy/fmt/format.h"
            instantiation of "auto fmt::v8::make_args_checked<Args...,S,Char>(const S &, const fmt::v8::remove_reference_t<Args> &...)->fmt::v8::format_arg_store<fmt::v8::buffer_context<Char>, fmt::v8::remove_reference_t<Args>...> [with Args=<fmt::v8::group_digits_view<int>>, S=char [19], Char=char]" at line 131 of "../fmt_copy/fmt/ostream.h"
            instantiation of "void fmt::v8::print(std::basic_ostream<Char, std::char_traits<Char>> &, const S &, Args &&...) [with S=char [19], Args=<fmt::v8::group_digits_view<int>>, Char=char]" at line 10 of "test-1.C"

compilation aborted for test-1.C (code 2)

The intel compiler version is:

>>>> icpc --version
icpc (ICC) 19.1.3.304 20200925
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.

I am using fmt-8.1.0

@gsjaardema
Copy link
Contributor Author

Note that this works:

#include <fmt/format.h>
#include <fmt/ostream.h>
#include <string>

int main()
{
  int age = 56;
  fmt::print(stderr, "I am {} years old\n", fmt::group_digits(age));
}

@sunmy2019
Copy link
Contributor

sunmy2019 commented Feb 8, 2022

This looks like a compiler bug.

After several digging, the static assertion failure directly due to the inconsistency of the following code: https://godbolt.org/z/3W3zY7z1E

fmt::detail::has_const_formatter<fmt::group_digits_view,
fmt::format_context>()
// should be true, but compile to false in some older versions of ICC.
The root cause is an overload resolution failure:

fmt/include/fmt/core.h

Lines 701 to 715 in ecd6022

template <typename Context, typename T>
constexpr auto has_const_formatter_impl(T*)
-> decltype(typename Context::template formatter_type<T>().format(
std::declval<const T&>(), std::declval<Context&>()),
true) {
return true;
}
template <typename Context>
constexpr auto has_const_formatter_impl(...) -> bool {
return false;
}
template <typename T, typename Context>
constexpr auto has_const_formatter() -> bool {
return has_const_formatter_impl<Context>(static_cast<T*>(nullptr));
}

ICC complains about the first overload

note: this candidate was rejected because there is a type mismatch after argument substitution
constexpr auto has_const_formatter_impl(T*)
^
detected during instantiation of "auto fmt::v8::detail::has_const_formatter<T,Context>()->bool [with T=fmt::v8::group_digits_view, Context=fmt::v8::format_context]" at line 3364

@sunmy2019
Copy link
Contributor

 fmt::print(errmsg, "I am {} years old\n", fmt::group_digits(age));

This use the make_args_checked, requiring its args being const.

 fmt::print(stderr, "I am {} years old\n", fmt::group_digits(age));

This uses make_format_args, not requiring its args being const.

fmt/include/fmt/core.h

Lines 1428 to 1432 in ecd6022

template <typename T, typename U = remove_cvref_t<T>>
struct formattable
: bool_constant<has_const_formatter<U, Context>() ||
!std::is_const<remove_reference_t<T>>::value ||
has_fallback_formatter<U, char_type>::value> {};

While there's is a bug in the compiler, the lack of constness in the latter case makes it formattable.

@gsjaardema
Copy link
Contributor Author

Is there an easy/involved workaround that I can use since fixing the intel compiler is not a possibility...

@vitaut
Copy link
Contributor

vitaut commented Feb 9, 2022

Thanks @sunmy2019 for investigating the issue. make_args_checked is a legacy internal API that should be replaced with make_format_args. A PR would be welcome.

@gsjaardema
Copy link
Contributor Author

I have a potential PR in progress -- but I am having problems with xchar.h. Basically, I am replacing:

-                    fmt::make_args_checked<Args...>(format_str, args...));
+                   fmt::make_format_args(args...));

Everything seems to work with this simple change except xchar.h. The errors I am getting are:

/Users/gdsjaar/src/fmt.fork/include/fmt/xchar.h:96:17: error: no matching function for call to 'vformat(fmt::v8::basic_string_view<wchar_t>, const fmt::v8::format_arg_store<fmt::v8::basic_format_context<fmt::v8::appender, char>, wchar_t>&)'
   96 |   return vformat(to_string_view(format_str), vargs);
      |          ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I am definitely out of my league here and hoped that a simple "pattern matching" change without deep understanding would work, but it obviously isn't. I can wait for someone else to create a PR, or if you want me to continue, any input / direction would be appreciated.

@phprus
Copy link
Contributor

phprus commented Feb 9, 2022

@gsjaardema
Check the branch https://github.com/phprus/fmt/tree/issue-2746 please.

@gsjaardema
Copy link
Contributor Author

gsjaardema commented Feb 9, 2022

@phprus
That is very similar to my change. However, i also changed fmt::make_args_checked to fmt::make_format_args in:

  • include/fmt/color.h
  • include/fmt/format.h
  • include/fmt/ostream.h
  • include/fmt/xchar.h

The removal from include/fmt/xchar.h seems to be the one giving problems. Since that seems to be included (at least from format.h) only if FMT_DEPRECATED_INCLUDE_XCHAR is defined, then maybe the change shouldn't be made to that file?

See https://github.com/gsjaardema/fmt/tree/remove-legacy-internal-api

@phprus
Copy link
Contributor

phprus commented Feb 10, 2022

@gsjaardema
xchar.h is needed for wchar_t strings. For details see the release notes https://github.com/fmtlib/fmt/releases/tag/8.0.0.

Please check my branch with intel compiler.
If it works and you don't mind, I'll create a PR.

@gsjaardema
Copy link
Contributor Author

Your branch was an improvement. I am now getting a similar error in a different line of code:

>>> icpc -I..private_copy_fmt/ test-1.C
..private_copy_fmt/fmt/core.h(1697): error: static assertion failed with "Cannot format a const argument."
    static_assert(formattable_const, "Cannot format a const argument.");
    ^
          detected during:
            instantiation of "auto fmt::v8::detail::make_arg<IS_PACKED,Context,<unnamed>,T,<unnamed>>(T &&)->fmt::v8::detail::value<Context> [with IS_PACKED=true, Context=fmt::v8::buffer_context<char>, <unnamed>=fmt::v8::detail::type::custom_type, T=const fmt::v8::remove_cvref_t<fmt::v8::group_digits_view<int> &> &, <unnamed>=0]" at line 1839
            instantiation of "fmt::v8::format_arg_store<Context, Args...>::format_arg_store(T &&...) [with Context=fmt::v8::buffer_context<char>, Args=<fmt::v8::group_digits_view<int>>, T=<const fmt::v8::remove_cvref_t<fmt::v8::group_digits_view<int> &> &>]" at line 1855
            instantiation of "auto fmt::v8::make_format_args(Args &&...)->fmt::v8::format_arg_store<Context, fmt::v8::remove_cvref_t<Args>...> [with Context=fmt::v8::buffer_context<char>, Args=<const fmt::v8::group_digits_view<int> &>]" at line 597 of "..private_copy_fmt/fmt/color.h"
            instantiation of "std::__cxx11::basic_string<Char, std::char_traits<Char>, std::allocator<Char>> fmt::v8::format(const fmt::v8::text_style &, const S &, const Args &...) [with S=char [19], Args=<fmt::v8::group_digits_view<int>>, Char=char]" at line 14 of "test-1.C"

compilation aborted for test-1.C (code 2)
cat test-1.C
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <fmt/color.h>
#include <string>
#include <sstream>

int main()
{
  std::ostringstream errmsg;
  int age = 56;
  auto fage = fmt::group_digits(age);
  fmt::print(errmsg, "I am {} years old\n", fage);
  fmt::print(stderr, "{}", 
	fmt::format(fg(fmt::color::cyan), "I am {} years old\n", fmt::group_digits(age)));
}

Maybe there is a better way to get colored output to a specific stream or this is now invalid syntax...

@phprus
Copy link
Contributor

phprus commented Feb 10, 2022

Line 1697 in core.h does not contain static_assert.
https://github.com/phprus/fmt/blob/issue-2746/include/fmt/core.h#L1697

Are you sure the correct fmt library files (branch https://github.com/phprus/fmt/tree/issue-2746) are being used?

@gsjaardema
Copy link
Contributor Author

Sorry, my core.h has the following added to the beginning:

+#ifndef FMT_HEADER_ONLY
+#define FMT_HEADER_ONLY
+#endif
+
On branch issue-2746
Your branch is up to date with 'origin/issue-2746'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   core.h

no changes added to commit (use "git add" and/or "git commit -a")

Here is the diff:

diff --git a/include/fmt/core.h b/include/fmt/core.h
index 4dc83ddf..309c5b64 100644
--- a/include/fmt/core.h
+++ b/include/fmt/core.h
@@ -15,6 +15,10 @@
 #include <string>
 #include <type_traits>
 
+#ifndef FMT_HEADER_ONLY
+#define FMT_HEADER_ONLY
+#endif
+
 // The fmt library version in the form major * 10000 + minor * 100 + patch.
 #define FMT_VERSION 80101

Without those changes, it would be line 1693 of your file...

@phprus
Copy link
Contributor

phprus commented Feb 10, 2022

make_format_args doesn't help.

I added disabling this check similar to MSVC:
https://github.com/phprus/fmt/blob/f4414840786d7764cce3f9cb9ba3fb88dc8753bd/include/fmt/core.h#L1434-L1448

Please check the branch https://github.com/phprus/fmt/tree/issue-2746 again.

And apply commit phprus@f441484 over current fmt master and check it.

@gsjaardema
Copy link
Contributor Author

Yes, this seems to fix the issue on both the issue-2746 branch and current master with the #f441484 patch.
Thank you.

I did notice that when I build with the issue-2746 branch, it is asserting:

private_copy_fmt/fmt/core.h(1689): warning #1595: non-POD (Plain Old Data) class type passed through ellipsis
    const auto& arg = arg_mapper<Context>().map(std::forward<T>(val));
                                                ^
          detected during:
            instantiation of "auto fmt::v8::detail::make_arg<IS_PACKED,Context,<unnamed>,T,<unnamed>>(T &&)->fmt::v8::detail::value<Context> [with IS_PACKED=true, Context=fmt::v8::format_context, <unnamed>=fmt::v8::detail::type::custom_type, T=const Ioss::ZoneConnectivity &, <unnamed>=0]" at line 1839
            instantiation of "fmt::v8::format_arg_store<Context, Args...>::format_arg_store(T &&...) [with Context=fmt::v8::format_context, Args=<Ioss::ZoneConnectivity>, T=<const Ioss::ZoneConnectivity &>]" at line 1855
            instantiation of "auto fmt::v8::make_format_args(Args &&...)->fmt::v8::format_arg_store<Context, fmt::v8::remove_cvref_t<Args>...> [with Context=fmt::v8::format_context, Args=<const Ioss::ZoneConnectivity &>]" at line 3195
            instantiation of "void fmt::v8::print(fmt::v8::format_string<T...>, T &&...) [with T=<const Ioss::ZoneConnectivity &>]" at line 241 of "src/main/io_info.C"

private_copy_fmt/fmt/core.h(1710): error: static assertion failed with "Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt"
    static_assert(
    ^
          detected during:
            instantiation of "auto fmt::v8::detail::make_arg<IS_PACKED,Context,<unnamed>,T,<unnamed>>(T &&)->fmt::v8::detail::value<Context> [with IS_PACKED=true, Context=fmt::v8::format_context, <unnamed>=fmt::v8::detail::type::custom_type, T=const Ioss::ZoneConnectivity &, <unnamed>=0]" at line 1839
            instantiation of "fmt::v8::format_arg_store<Context, Args...>::format_arg_store(T &&...) [with Context=fmt::v8::format_context, Args=<Ioss::ZoneConnectivity>, T=<const Ioss::ZoneConnectivity &>]" at line 1855
            instantiation of "auto fmt::v8::make_format_args(Args &&...)->fmt::v8::format_arg_store<Context, fmt::v8::remove_cvref_t<Args>...> [with Context=fmt::v8::format_context, Args=<const Ioss::ZoneConnectivity &>]" at line 3195
            instantiation of "void fmt::v8::print(fmt::v8::format_string<T...>, T &&...) [with T=<const Ioss::ZoneConnectivity &>]" at line 241 of "src/main/io_info.C"

The Ioss::ZoneConnectivity class has an friend std::ostream &operator<< defined on it which seems to work on current master, but fails on the issue-2746 branch code...

@phprus
Copy link
Contributor

phprus commented Feb 10, 2022

master with patch #f441484 raises this error too?
Or issue-2746 branch only?

@gsjaardema
Copy link
Contributor Author

gsjaardema commented Feb 10, 2022

Master with patch does not raise the error; only issue-2746 branch.

@phprus
Copy link
Contributor

phprus commented Feb 11, 2022

I created a PR #2758 from a commit phprus@f441484. It must solve the issue.

But replacing make_args_checked with make_format_args results in an error (#2746 (comment)). @vitaut , I need help.

@phprus
Copy link
Contributor

phprus commented Feb 11, 2022

Possibly similar issue: #2759

@phprus
Copy link
Contributor

phprus commented Feb 11, 2022

@gsjaardema,
Please, check my branch issue-2746 with define FMT_DEPRECATED_OSTREAM macro.

@vitaut
Copy link
Contributor

vitaut commented Feb 12, 2022

Closing since the workaround has landed (thanks, @phprus!) Feel free to reopen if this didn't help but note that the ostream error is unrelated and can be fixed by either defining FMT_DEPRECATED_OSTREAM or adding a formatter specialization.

@jiapei100
Copy link

Mark this... Finally, find this issue... Thank you ....

@jiapei-nexera
Copy link

It looks the same issue happened when I tried to build https://github.com/isl-org/Open3D .

This PR #2758 does NOT work...

@barracuda156
Copy link

Just got the same error when building log4cxx with gcc12 for Darwin PPC:

In file included from /opt/local/var/macports/build/_opt_PPCRosettaPorts_devel_log4cxx/log4cxx/work/apache-log4cxx-0.13.0/src/examples/cpp/format-string.cpp:21:
/opt/local/include/fmt/core.h: In instantiation of 'constexpr fmt::v9::detail::value<Context> fmt::v9::detail::make_value(T&&) [with Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; T = MyStruct&]':
/opt/local/include/fmt/core.h:1753:29:   required from 'constexpr fmt::v9::detail::value<Context> fmt::v9::detail::make_arg(T&&) [with bool IS_PACKED = true; Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; type <anonymous> = fmt::v9::detail::type::custom_type; T = MyStruct&; typename std::enable_if<IS_PACKED, int>::type <anonymous> = 0]'
/opt/local/include/fmt/core.h:1877:77:   required from 'constexpr fmt::v9::format_arg_store<Context, Args>::format_arg_store(T&& ...) [with T = {MyStruct&}; Context = fmt::v9::basic_format_context<fmt::v9::appender, char>; Args = {MyStruct}]'
/opt/local/include/fmt/core.h:1894:38:   required from 'constexpr fmt::v9::format_arg_store<Context, typename std::remove_cv<typename std::remove_reference<Args>::type>::type ...> fmt::v9::make_format_args(Args&& ...) [with Context = basic_format_context<appender, char>; Args = {MyStruct&}]'
/opt/local/include/fmt/core.h:3163:44:   required from 'std::string fmt::v9::format(format_string<T ...>, T&& ...) [with T = {MyStruct&}; std::string = std::basic_string<char>; format_string<T ...> = basic_format_string<char, MyStruct&>]'
/opt/local/var/macports/build/_opt_PPCRosettaPorts_devel_log4cxx/log4cxx/work/apache-log4cxx-0.13.0/src/examples/cpp/format-string.cpp:50:2:   required from here
/opt/local/include/fmt/core.h:1733:7: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
 1733 |       formattable,
      |       ^~~~~~~~~~~
/opt/local/include/fmt/core.h:1733:7: note: 'formattable' evaluates to false
[ 99%] Built target custom-appender
make[2]: *** [src/examples/cpp/CMakeFiles/format-string.dir/format-string.cpp.o] Error 1
make[2]: Leaving directory `/opt/local/var/macports/build/_opt_PPCRosettaPorts_devel_log4cxx/log4cxx/work/build'
make[1]: *** [src/examples/cpp/CMakeFiles/format-string.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants