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.

Reply via email to