diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 014e027b..6bced99b 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -33,6 +33,10 @@ jobs: std: 23 install: sudo apt install g++-13 shared: -DBUILD_SHARED_LIBS=ON + - cxx: g++-14 + build_type: Release + std: 23 + install: sudo apt install g++-14 - cxx: clang++-11 build_type: Debug std: 17 @@ -55,6 +59,11 @@ jobs: std: 20 cxxflags: -stdlib=libc++ install: sudo apt install libc++-14-dev libc++abi-14-dev + - cxx: clang++-20 + build_type: Debug + std: 20 + cxxflags: -stdlib=libc++ + install: sudo apt install clang-20 libc++-20-dev libc++abi-20-dev steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 @@ -131,7 +140,14 @@ jobs: - name: Add repositories for newer GCC run: | sudo apt-add-repository ppa:ubuntu-toolchain-r/test - if: ${{ matrix.cxx == 'g++-13' }} + if: ${{ matrix.cxx == 'g++-13' || matrix.cxx == 'g++-14' }} + + - name: Install LLVM-20 + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 20 + if: ${{ matrix.cxx == 'clang++-20' }} - name: Add Ubuntu mirrors run: | @@ -164,6 +180,23 @@ jobs: -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \ -DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON \ ${{matrix.fuzz}} ${{matrix.shared}} $GITHUB_WORKSPACE + if: ${{ matrix.cxx != 'clang++-20' && matrix.cxx != 'g++-14' }} + + - name: Configure-Modules + working-directory: ${{runner.workspace}}/build + env: + CXX: ${{matrix.cxx}} + CXXFLAGS: ${{matrix.cxxflags}} + run: | + cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ + -DCMAKE_CXX_STANDARD=${{matrix.std}} \ + -DCMAKE_CXX_EXTENSIONS=OFF \ + -G Ninja \ + -DCMAKE_CXX_VISIBILITY_PRESET=hidden \ + -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \ + -DFMT_DOC=OFF -DFMT_PEDANTIC=ON \ + ${{matrix.fuzz}} ${{matrix.shared}} $GITHUB_WORKSPACE + if: ${{ matrix.cxx == 'clang++-20' || matrix.cxx == 'g++-14' }} - name: Build working-directory: ${{runner.workspace}}/build diff --git a/include/fmt/base.h b/include/fmt/base.h index bf9347e0..3c629859 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -1859,42 +1859,38 @@ class fixed_buffer_traits { }; template -struct has_back_insert_iterator_container_append : std::false_type {}; +struct has_append : std::false_type {}; template -struct has_back_insert_iterator_container_append< - OutputIt, InputIt, - void_t()) - .append(std::declval(), - std::declval()))>> : std::true_type {}; +struct has_append()) + .append(std::declval(), + std::declval()))>> + : std::true_type {}; -template -struct has_back_insert_iterator_container_insert_at_end : std::false_type {}; +template +struct has_insert : std::false_type {}; -template -struct has_back_insert_iterator_container_insert_at_end< - OutputIt, InputIt, - void_t()) - .insert(get_container(std::declval()).end(), - std::declval(), - std::declval()))>> : std::true_type {}; +template +struct has_insert()) + .insert({}, std::declval(), + std::declval()))>> + : std::true_type {}; // An optimized version of std::copy with the output value type (T). template ::value&& - has_back_insert_iterator_container_append< - OutputIt, InputIt>::value)> + FMT_ENABLE_IF(is_back_insert_iterator() && + has_append())> FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { get_container(out).append(begin, end); return out; } template ::value && - !has_back_insert_iterator_container_append< - OutputIt, InputIt>::value && - has_back_insert_iterator_container_insert_at_end< - OutputIt, InputIt>::value)> + FMT_ENABLE_IF(is_back_insert_iterator() && + !has_append() && + has_insert())> FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { auto& c = get_container(out); c.insert(c.end(), begin, end); @@ -1902,21 +1898,14 @@ FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { } template ::value && - (has_back_insert_iterator_container_append< - OutputIt, InputIt>::value || - has_back_insert_iterator_container_insert_at_end< - OutputIt, InputIt>::value)))> + FMT_ENABLE_IF(!is_back_insert_iterator() || + !(has_append() || + has_insert()))> FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { while (begin != end) *out++ = static_cast(*begin++); return out; } -template -FMT_CONSTEXPR auto copy(basic_string_view s, OutputIt out) -> OutputIt { - return copy(s.begin(), s.end(), out); -} - // A buffer that writes to an output iterator when flushed. template class iterator_buffer : public Traits, public buffer { @@ -1934,12 +1923,7 @@ class iterator_buffer : public Traits, public buffer { this->clear(); const T* begin = data_; const T* end = begin + this->limit(size); -#if defined(__cpp_if_constexpr) - if constexpr (std::is_move_assignable::value) - out_ = copy(begin, end, out_); - else -#endif - while (begin != end) *out_++ = *begin++; + out_ = copy(begin, end, out_); } public: diff --git a/include/fmt/format.h b/include/fmt/format.h index c93d85ac..96c21329 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -548,6 +548,11 @@ FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { return out + count; } +template +FMT_CONSTEXPR auto copy(basic_string_view s, OutputIt out) -> OutputIt { + return copy(s.begin(), s.end(), out); +} + template FMT_CONSTEXPR FMT_NOINLINE auto copy_noinline(InputIt begin, InputIt end, OutputIt out) -> OutputIt { diff --git a/test/base-test.cc b/test/base-test.cc index bf268875..9575e055 100644 --- a/test/base-test.cc +++ b/test/base-test.cc @@ -811,10 +811,10 @@ TEST(base_test, throw_in_buffer_dtor) { constexpr int buffer_size = 256; struct throwing_iterator { - int& count; + int* count; auto operator=(char) -> throwing_iterator& { - if (++count > buffer_size) throw std::exception(); + if (++*count > buffer_size) throw std::exception(); return *this; } auto operator*() -> throwing_iterator& { return *this; } @@ -824,7 +824,7 @@ TEST(base_test, throw_in_buffer_dtor) { try { int count = 0; - fmt::format_to(throwing_iterator{count}, fmt::runtime("{:{}}{"), "", + fmt::format_to(throwing_iterator{&count}, fmt::runtime("{:{}}{"), "", buffer_size + 1); } catch (const std::exception&) { }