https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90454
Bug ID: 90454 Summary: filesystem::path template constructor void* overload interference Product: gcc Version: 8.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: patrick.a.moran at gmail dot com Target Milestone: --- Created attachment 46349 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46349&action=edit A reproduction of the issue described I've marked the issue as 8.1.0 because that's the earliest version I've confirmed it on, but I've seen it on 8.2.0, 8.3.0, 9.1.0, and the version that godbolt.org was calling "HEAD" on 2019.05.10. I suspect it has been there as long as <filesystem> has been present. I attached a short reproduction. The end-user symptom is that if you have two overloads of a function, one taking std::filesystem::path (or a const reference thereto) and another taking void* (or a const reference thereto), then you won't be able to pass a void* to the void*-taking function. You will get ${GCC_INSTALL}/include/c++/9.1.0/bits/stl_iterator_base_types.h: In instantiation of ‘struct std::iterator_traits<void*>’: ${GCC_INSTALL}/include/c++/9.1.0/bits/fs_path.h:82:13: required by substitution of ‘template<class _Iter, class _Iter_traits> using __is_path_iter_src = std::__and_<std::filesystem::__cxx11::path::__is_encoded_char<typename _Iter_traits::value_type, type\ name std::remove_const<typename _Iter_traits::value_type>::type>, std::is_base_of<std::input_iterator_tag, typename _Iter_traits::iterator_category> > [with _Iter = void*; _Iter_traits = std::iterator_traits<void*>]’ ${GCC_INSTALL}/include/c++/9.1.0/bits/fs_path.h:89:7: required by substitution of ‘template<class _Iter> static std::filesystem::__cxx11::path::__is_path_iter_src<_Iter> std::filesystem::__cxx11::path::__is_path_src(_Iter, int) [with _Iter = void*]’ ${GCC_INSTALL}/include/c++/9.1.0/bits/fs_path.h:113:31: required from ‘struct std::filesystem::__cxx11::path::__constructible_from<void*, void>’ ${GCC_INSTALL}/include/c++/9.1.0/type_traits:131:12: required from ‘struct std::__and_<std::__not_<std::is_void<void*> >, std::filesystem::__cxx11::path::__constructible_from<void*, void> >’ ${GCC_INSTALL}/include/c++/9.1.0/type_traits:136:12: required from ‘struct std::__and_<std::__not_<std::is_same<void*, std::filesystem::__cxx11::path> >, std::__not_<std::is_void<void*> >, std::filesystem::__cxx11::path::__constructible_from<void*, void>\ >’ ${GCC_INSTALL}/include/c++/9.1.0/bits/fs_path.h:117:13: 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, st\ d::filesystem::__cxx11::path> >, std::__not_<std::is_void<_Tp> >, std::filesystem::__cxx11::path::__constructible_from<_Tp1, _Tp2> >::value, std::filesystem::__cxx11::path>::type [with _Tp1 = void*; _Tp2 = void]’ ${GCC_INSTALL}/include/c++/9.1.0/bits/fs_path.h:190:7: required by substitution of ‘template<class _Source, class _Require> std::filesystem::__cxx11::path::path(const _Source&, std::filesystem::__cxx11::path::format) [with _Source = void*; _Require = <mi\ ssing>]’ path_repro.cpp:7:21: required from here ${GCC_INSTALL}/include/c++/9.1.0/bits/stl_iterator_base_types.h:184:43: error: forming reference to void 184 | typedef _Tp& reference; | ^~~~~~~~~ I've traced the issue this far: std::filesystem::path has a predicate __is_path_iter_src that is used through a chain of dependencies to conditionally enable constructor #5 from 30.11.7.4.1 - the one taking a template Source argument. That argument is supposed to be string-like, and 30.11.7.3 2 specifies that the constructor not take part in overload resolution unless for the Source argument "the qualified-id iterator_traits<decay_t<Source>>::value_type is valid and denotes a possibly const encoded character type" The problem is that actually instantiating std::iterator_traits<void*> triggers that "forming reference to void" error. Because of this, constructor 5 is not being removed from the set of overloads, we're encountering a compilation failure while in the process of determining if it should participate in overload resolution. The way this relates to the end-user symptom is that this compile-failure will break the user's build, even though the overload that takes void* would be the better match.