#include <concepts> #include <filesystem> struct Foo { Foo(const std::filesystem::path& p); }; static_assert(std::copyable<Foo>); Error: In file included from <source>:1: /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<Foo>': /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:84:11: required by substitution of 'template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::__or_<std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char8_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, wchar_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char16_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char32_t> >, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = Foo; _Iter_traits = std::iterator_traits<Foo>]' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:91:5: required by substitution of 'template<class _Iter> std::filesystem::__cxx11::__detail::__is_path_iter_src<_Iter> std::filesystem::__cxx11::__detail::__is_path_src(_Iter, int) [with _Iter = Foo]' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:115:29: required from 'struct std::filesystem::__cxx11::__detail::__constructible_from<Foo, void>' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:138:12: required from 'struct std::__and_<std::__not_<std::is_void<Foo> >, std::filesystem::__cxx11::__detail::__constructible_from<Foo, void> >' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:143:12: required from 'struct std::__and_<std::__not_<std::is_same<Foo, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<Foo> >, std::filesystem::__cxx11::__detail::__constructible_from<Foo, void> >' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:119:11: required by substitution of 'template<class _Tp1, class _Tp2> using _Path = typename std::enable_if<std::__and_<std::__not_<std::is_same<typename std::remove_cv< <template-parameter-1-1> >::type, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<typename std::remove_pointer<_Tp>::type> >, std::filesystem::__cxx11::__detail::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = Foo; _Tp2 = void]' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/bits/fs_path.h:219:7: required by substitution of 'template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = Foo; _Require = <missing>]' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:901:30: required from 'struct std::__is_constructible_impl<Foo, Foo>' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:906:12: required from 'struct std::is_constructible<Foo, Foo>' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:3107:25: required from 'constexpr const bool std::is_constructible_v<Foo, Foo>' /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/concepts:139:30: required from here /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/concepts:139:30: error: the value of 'std::is_constructible_v<Foo, Foo>' is not usable in a constant expression 139 | = destructible<_Tp> && is_constructible_v<_Tp, _Args...>; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/concepts:44, from <source>:1: /opt/compiler-explorer/gcc-trunk-20200229/include/c++/10.0.1/type_traits:3107:25: note: 'std::is_constructible_v<Foo, Foo>' used in its own initializer 3107 | inline constexpr bool is_constructible_v = | ^~~~~~~~~~~~~~~~~~
Here's a shorter reproduction without filesystem: #include <concepts> #include <iterator> struct path { template <typename Source, typename = std::enable_if_t< std::is_same_v< std::iterator_traits<Source>::value_type, char>> > path(Source const&); }; struct Bar { Bar(const path& p); }; #ifdef ADD_THIS static_assert(!std::constructible_from<path, Bar>); #endif static_assert(std::copyable<Bar>); If ADD_THIS isn't defined, the copyable check is a hard error. If it is defined, compiles fine. https://godbolt.org/z/FEoiwA
(From Tim) This is LWG 3244.
This is nothing to do with concepts: #include <iterator> struct path { template <typename Source, typename = std::enable_if_t< std::is_same_v< std::iterator_traits<Source>::value_type, char>> > path(Source const&); }; struct Bar { Bar(const path& p); }; #ifdef ADD_THIS static_assert(!std::is_constructible_v<path, Bar>); #endif static_assert(std::is_copy_constructible_v<Bar>); See also PR 93923.
I got this error too. This is the code: #include <filesystem> #include <concepts> struct A { A() = default; A(A const&) = default; A & operator = (A const&) = default; A(std::filesystem::path); // This line triggers the error. }; static_assert(std::semiregular<A>); There is no reason why an extra constructor would affect the semiregularity of a type. $> g++ -std=c++20 In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/compare:39, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_pair.h:65, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_algobase.h:64, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/char_traits.h:39, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/string:40, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:39, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44, from <source>:1: /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<A>': /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:84:11: required by substitution of 'template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::__or_<std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char8_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, wchar_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char16_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char32_t> >, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = A; _Iter_traits = std::iterator_traits<A>]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:91:5: required by substitution of 'template<class _Iter> std::filesystem::__cxx11::__detail::__is_path_iter_src<_Iter> std::filesystem::__cxx11::__detail::__is_path_src(_Iter, int) [with _Iter = A]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:115:29: required from 'struct std::filesystem::__cxx11::__detail::__constructible_from<A, void>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:138:12: required from 'struct std::__and_<std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:143:12: required from 'struct std::__and_<std::__not_<std::is_same<A, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:119:11: required by substitution of 'template<class _Tp1, class _Tp2> using _Path = typename std::enable_if<std::__and_<std::__not_<std::is_same<typename std::remove_cv< <template-parameter-1-1> >::type, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<typename std::remove_pointer<_Tp>::type> >, std::filesystem::__cxx11::__detail::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = A; _Tp2 = void]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:219:7: required by substitution of 'template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = A; _Require = <missing>]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:901:30: required from 'struct std::__is_constructible_impl<A, A>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:906:12: required from 'struct std::is_constructible<A, A>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25: required from 'constexpr const bool std::is_constructible_v<A, A>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30: required from here /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30: error: the value of 'std::is_constructible_v<A, A>' is not usable in a constant expression 139 | = destructible<_Tp> && is_constructible_v<_Tp, _Args...>; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/move.h:57, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/nested_exception.h:40, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/exception:148, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:38, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44, from <source>:1: /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25: note: 'std::is_constructible_v<A, A>' used in its own initializer 3091 | inline constexpr bool is_constructible_v = | ^~~~~~~~~~~~~~~~~~ ASM generation compiler returned: 1 In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/compare:39, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_pair.h:65, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_algobase.h:64, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/char_traits.h:39, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/string:40, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:39, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44, from <source>:1: /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/stl_iterator_base_types.h: In instantiation of 'struct std::iterator_traits<A>': /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:84:11: required by substitution of 'template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::__or_<std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char8_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, wchar_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char16_t>, std::is_same<typename std::remove_const<typename _Iter_traits::value_type>::type, char32_t> >, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = A; _Iter_traits = std::iterator_traits<A>]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:91:5: required by substitution of 'template<class _Iter> std::filesystem::__cxx11::__detail::__is_path_iter_src<_Iter> std::filesystem::__cxx11::__detail::__is_path_src(_Iter, int) [with _Iter = A]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:115:29: required from 'struct std::filesystem::__cxx11::__detail::__constructible_from<A, void>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:138:12: required from 'struct std::__and_<std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:143:12: required from 'struct std::__and_<std::__not_<std::is_same<A, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<A> >, std::filesystem::__cxx11::__detail::__constructible_from<A, void> >' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:119:11: required by substitution of 'template<class _Tp1, class _Tp2> using _Path = typename std::enable_if<std::__and_<std::__not_<std::is_same<typename std::remove_cv< <template-parameter-1-1> >::type, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<typename std::remove_pointer<_Tp>::type> >, std::filesystem::__cxx11::__detail::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = A; _Tp2 = void]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_path.h:219:7: required by substitution of 'template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = A; _Require = <missing>]' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:901:30: required from 'struct std::__is_constructible_impl<A, A>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:906:12: required from 'struct std::is_constructible<A, A>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25: required from 'constexpr const bool std::is_constructible_v<A, A>' /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30: required from here /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/concepts:139:30: error: the value of 'std::is_constructible_v<A, A>' is not usable in a constant expression 139 | = destructible<_Tp> && is_constructible_v<_Tp, _Args...>; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/move.h:57, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/nested_exception.h:40, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/exception:148, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/stdexcept:38, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/system_error:41, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/bits/fs_fwd.h:35, from /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/filesystem:44, from <source>:1: /opt/compiler-explorer/gcc-trunk-20200321/include/c++/10.0.1/type_traits:3091:25: note: 'std::is_constructible_v<A, A>' used in its own initializer 3091 | inline constexpr bool is_constructible_v = | ^~~~~~~~~~~~~~~~~~
(In reply to Paco Arjonilla from comment #4) > There is no reason why an extra constructor would affect the semiregularity > of a type. That's not true. A private or deleted constructor that is a better match for some arguments can affect it.
It seems that I hit the same issue when making us of ranges: ```c++ #include <filesystem> #include <ranges> static_assert(std::input_iterator<int *>); struct alignment_file_input { alignment_file_input(std::filesystem::path); template <typename stream_t> alignment_file_input(stream_t); int* begin(); int* end(); }; static_assert(std::ranges::input_range<alignment_file_input>); int main() { alignment_file_input fin{int{}}; auto && view = fin | std::views::take(1); } ``` https://godbolt.org/z/__hw9w
(In reply to Lyberta from comment #0) > #include <concepts> > #include <filesystem> > > struct Foo > { > Foo(const std::filesystem::path& p); > }; > > static_assert(std::copyable<Foo>); The problem is that copyable<Foo> considers the Foo(const path&) constructor to see if it can be called with a const Foo&. That considers this constructor with Foo substituted for Source: filesystem::path(Source const&, format = auto_format); The constraints for Source involve checking whether Source is a Cpp17InputIterator, which is done with this: template<typename _Iter, typename _Iter_traits = std::iterator_traits<_Iter>> using __is_path_iter_src = __and_<__is_encoded_char<typename _Iter_traits::value_type>, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category>>; So we instantiate iterator_traits<Foo>. In C++20 finding the matching specialization for std::iterator_traits<Foo> checks for concept satisfaction, which includes checking copyable<Foo> which is recursive. An even smaller reproducer is: #include <iterator> struct X { template<typename T, typename = std::iterator_traits<T>::iterator_category> X(const T&); }; static_assert( std::copyable<X> ); I can fix filesystem::path to avoid using iterator_traits, but this seems like it's going to cause problems for plenty of other code too.
(really from Tim) This is https://cplusplus.github.io/LWG/issue3420
Thanks, Tim. I'd forgotten about that issue and was about to reinvent the resolution.
*** Bug 95233 has been marked as a duplicate of this bug. ***
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:f094665d465cdf8903797cc58bea13007e588616 commit r11-541-gf094665d465cdf8903797cc58bea13007e588616 Author: Jonathan Wakely <jwakely@redhat.com> Date: Thu May 21 07:32:15 2020 +0100 libstdc++: Avoid constraint recursion with iterator_traits (PR 93983) Checking whether a filesystem::path constructor argument is an iterator requires instantiating std::iterator_traits. In C++20 that checks for satisfaction of std::iterator_traits constraints, which checks if the type is copyable, which can end up recursing back to the path constructor. The fix in LWG 3420 is to reorder the cpp17-iterator concept's constraints to check if the type looks vaguely like an iterator before checking copyable. That avoids the recursion for types which definitely aren't iterators, but isn't foolproof. PR libstdc++/93983 * include/bits/iterator_concepts.h (__detail::__cpp17_iterator): Reorder constraints to avoid recursion when constructors use iterator_traits (LWG 3420). * testsuite/24_iterators/customization_points/lwg3420.cc: New test.
The releases/gcc-10 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:566ba72126288272607374a32ac646dcd36fe584 commit r10-8163-g566ba72126288272607374a32ac646dcd36fe584 Author: Jonathan Wakely <jwakely@redhat.com> Date: Thu May 21 07:47:17 2020 +0100 libstdc++: Avoid constraint recursion with iterator_traits (PR 93983) Checking whether a filesystem::path constructor argument is an iterator requires instantiating std::iterator_traits. In C++20 that checks for satisfaction of std::iterator_traits constraints, which checks if the type is copyable, which can end up recursing back to the path constructor. The fix in LWG 3420 is to reorder the cpp17-iterator concept's constraints to check if the type looks vaguely like an iterator before checking copyable. That avoids the recursion for types which definitely aren't iterators, but isn't foolproof. Backport from mainline 2020-05-21 Jonathan Wakely <jwakely@redhat.com> PR libstdc++/93983 * include/bits/iterator_concepts.h (__detail::__cpp17_iterator): Reorder constraints to avoid recursion when constructors use iterator_traits (LWG 3420). * testsuite/24_iterators/customization_points/lwg3420.cc: New test.
Fixed for 10.2