fmt icon indicating copy to clipboard operation
fmt copied to clipboard

Building fails with "error: lvalue required as increment operand"

Open nlsweet opened this issue 1 year ago • 8 comments

Compiler is gcc 8.3.1

Can reproduce on godbolt with this code:

#include "fmt/format.h"

int main() {
  char buffer[4];
  auto result = fmt::format_to(buffer, "{}", 12345);

}

Output on godbolt:

In file included from /opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:41,
                 from <source>:2:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h: In instantiation of 'struct fmt::v11::detail::is_output_iterator<char [4], char, void>':
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:3025:11:   required by substitution of 'template<class OutputIt, class ... T, typename std::enable_if<fmt::v11::detail::is_output_iterator<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type, char>::value, int>::type <anonymous> > fmt::v11::remove_cvref_t<T> fmt::v11::format_to(OutputIt&&, fmt::v11::format_string<T ...>, T&& ...) [with OutputIt = char (&)[4]; T = {int}; typename std::enable_if<fmt::v11::detail::is_output_iterator<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type, char>::value, int>::type <anonymous> = <missing>]'
<source>:6:51:   required from here
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1583:48: error: lvalue required as increment operand
     It, T, void_t<decltype(*std::declval<It&>()++ = std::declval<T>())>>
                             ~~~~~~~~~~~~~~~~~~~^~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1583:48: error: lvalue required as increment operand
Compiler returned: 1

We discovered this issue when trying to build the fmt package after cloning the repo from github. After cloning, mkdir build && cd build && cmake .. && make

Output from this:

[ 16%] Building CXX object test/CMakeFiles/base-test.dir/base-test.cc.o
In file included from /home/nlsweet/external/fmt/test/base-test.cc:12:
/home/nlsweet/external/fmt/include/fmt/base.h: In instantiation of ‘struct fmt::v11::detail::is_output_iterator<char [4], char, void>’:
/home/nlsweet/external/fmt/include/fmt/base.h:2936:11:   required by substitution of ‘template<class OutputIt, class ... T, typename std::enable_if<fmt::v11::detail::is_output_iterator<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type, char>::value, int>::type <anonymous> > fmt::v11::remove_cvref_t<T> fmt::v11::format_to(OutputIt&&, fmt::v11::format_string<T ...>, T&& ...) [with OutputIt = char (&)[4]; T = {int}; typename std::enable_if<fmt::v11::detail::is_output_iterator<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type, char>::value, int>::type <anonymous> = <missing>]’
/home/nlsweet/external/fmt/test/base-test.cc:729:51:   required from here
/home/nlsweet/external/fmt/include/fmt/base.h:1576:48: error: lvalue required as increment operand
     It, T, void_t<decltype(*std::declval<It&>()++ = std::declval<T>())>>
                             ~~~~~~~~~~~~~~~~~~~^~
/home/nlsweet/external/fmt/include/fmt/base.h:1576:48: error: lvalue required as increment operand
make[2]: *** [test/CMakeFiles/base-test.dir/build.make:76: test/CMakeFiles/base-test.dir/base-test.cc.o] Error 1

nlsweet avatar Aug 27 '24 13:08 nlsweet

Please provide an actual godbolt link.

vitaut avatar Aug 27 '24 13:08 vitaut

Godbolt

nlsweet avatar Aug 27 '24 14:08 nlsweet

Godbolt

As a workaround, change to &buffer[0] or static_cast<char*>(buffer) there it works fine @nlsweet

Arghnews avatar Aug 27 '24 18:08 Arghnews

Well, that fixes the example on Godbolt, but base-test.cc (and probably other tests) is still broken when applying that change:

[ 16%] Building CXX object test/CMakeFiles/base-test.dir/base-test.cc.o
In file included from /home/nlsweet/external/fmt/test/test-assert.h:17,
                 from /home/nlsweet/external/fmt/test/base-test.cc:9:
/home/nlsweet/external/fmt/test/base-test.cc: In member function ‘virtual void base_test_format_to_array_Test::TestBody()’:
/home/nlsweet/external/fmt/test/base-test.cc:724:49: error: request for member ‘out’ in ‘result’, which is of non-class type ‘char*’
   EXPECT_EQ(4, std::distance(&buffer[0], result.out));
                                                 ^~~
In file included from /home/nlsweet/external/fmt/test/test-assert.h:17,
                 from /home/nlsweet/external/fmt/test/base-test.cc:9:
/home/nlsweet/external/fmt/test/base-test.cc:725:22: error: request for member ‘truncated’ in ‘result’, which is of non-class type ‘char*’
   EXPECT_TRUE(result.truncated);
                      ^~~~~~~~~
In file included from /home/nlsweet/external/fmt/test/test-assert.h:17,
                 from /home/nlsweet/external/fmt/test/base-test.cc:9:
/home/nlsweet/external/fmt/test/base-test.cc:726:32: error: request for member ‘out’ in ‘result’, which is of non-class type ‘char*’
   EXPECT_EQ(buffer + 4, result.out);

nlsweet avatar Aug 27 '24 18:08 nlsweet

This is gcc 8.1 - 8.3 bug. Works on gcc < 8 or gcc >= 8.4:

https://godbolt.org/z/d11h3zqMq

phprus avatar Aug 27 '24 22:08 phprus

And yet those tests built and ran fine through the 10.2 releases.

Are you suggesting that {fmt} isn't as portable as claimed?

nlsweet avatar Aug 27 '24 22:08 nlsweet

@nlsweet I've put in a fix in https://github.com/fmtlib/fmt/pull/4131 that I've tested and now works on gcc 8.3.0, should fix it for you too

Arghnews avatar Aug 27 '24 22:08 Arghnews

All tests built and ran (and passed). Thank you, @Arghnews

nlsweet avatar Aug 27 '24 23:08 nlsweet