https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121646

            Bug ID: 121646
           Summary: `Substitution failure` does panic and aborts
                    everything
           Product: gcc
           Version: 15.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: shyeyian at petalmail dot com
  Target Milestone: ---

Example:
```
#include <concepts>
#include <string>

struct my_string
{
    private:
        char* ptr;
    public:
        operator std::string_view ( ) const
        {
            return std::string_view(ptr);
        }
        auto begin() const
        {
            return std::string_view(*this).begin();
        }
        auto end() const
        {
            return std::string_view(*this).end();
        }
};
int main() { }
```

Output (Linux, g++ 15.2.1):
```
[anonymous@matebook anonymous]$ g++ -std=c++26 tmp.cpp -o tmp.o
In file included from
/usr/include/c++/15.2.1/bits/stl_iterator_base_types.h:73,
                 from /usr/include/c++/15.2.1/bits/stl_construct.h:61,
                 from /usr/include/c++/15.2.1/bits/char_traits.h:59,
                 from /usr/include/c++/15.2.1/string:44,
                 from tmp.cpp:2:
/usr/include/c++/15.2.1/bits/ranges_base.h: In substitution of ‘template<class
_Tp>  requires (__maybe_borrowed_range<_Tp>) && ((is_array_v<typename
std::remove_reference<_Tp>::type>) || (__member_begin<_Tp>) ||
(__adl_begin<_Tp>)) constexpr auto
std::ranges::__access::_Begin::operator()(_Tp&&) const [with _Tp = const
my_string&]’:
/usr/include/c++/15.2.1/bits/ranges_base.h:516:15:   required by substitution
of ‘template<class _Range, class _DRange>  requires !(is_same_v<_DRange,
std::basic_string_view<_CharT, _Traits> >) && (contiguous_range<_Range>) &&
(sized_range<_Range>) && (is_same_v<typename
std::__detail::__iter_traits_impl<typename
std::remove_cvref<decltype(std::ranges::__access::__begin((declval<_Range&>)()))>::type,
std::indirectly_readable_traits<typename
std::remove_cvref<decltype(std::ranges::__access::__begin((declval<_Range&>)()))>::type>
>::__iter_traits<typename
std::remove_cvref<decltype(std::ranges::__access::__begin((declval<_Range&>)()))>::type,
std::indirectly_readable_traits<typename
std::remove_cvref<decltype(std::ranges::__access::__begin((declval<_Range&>)()))>::type>
>::value_type, _CharT>) && !(is_convertible_v<_Range, const _CharT*>) &&
!requires(_DRange& __d) {__d->__conv_op ();} constexpr
std::basic_string_view<char>::basic_string_view(_Range&&) [with _Range = const
my_string&; _DRange = my_string]’
  516 |         ranges::begin(__t);
      |         ~~~~~~~~~~~~~^~~~~
tmp.cpp:19:42:   required from here
   19 |             return std::string_view(*this).end();
      |                                          ^
/usr/include/c++/15.2.1/bits/iterator_concepts.h:1035:15:   required for the
satisfaction of ‘__member_begin<_Tp>’ [with _Tp = const my_string&]
/usr/include/c++/15.2.1/bits/iterator_concepts.h:1035:32:   in requirements
with ‘_Tp& __t’ [with _Tp = const my_string&]
/usr/include/c++/15.2.1/bits/iterator_concepts.h:1035:32: error: satisfaction
value of atomic constraint ‘requires(_Tp& __t)
{{std::ranges::__access::__decay_copy(__t->begin())} -> decltype(auto)
[requires std::input_or_output_iterator<<placeholder>, >];} [with _Tp = const
my_string&]’ changed from ‘false’ to ‘true’
 1035 |       concept __member_begin = requires(_Tp& __t)
      |                                ^~~~~~~~~~~~~~~~~~
 1036 |         {
      |         ~                       
 1037 |           { __decay_copy(__t.begin()) } -> input_or_output_iterator;
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1038 |         };
      |         ~                       
In file included from /usr/include/c++/15.2.1/string_view:58,
                 from /usr/include/c++/15.2.1/bits/basic_string.h:51,
                 from /usr/include/c++/15.2.1/string:56:
/usr/include/c++/15.2.1/bits/ranges_base.h:516:22: note: satisfaction value
first evaluated to ‘false’ from here
  516 |         ranges::begin(__t);
      |         ~~~~~~~~~~~~~^~~~~
[anonymous@matebook anonymous]$ 
```

You see, once we call `std::string_view(*this)`:
- We expect the `my_string::operator std::string_view` constructor here
- But according to the overload resolution, we should try all the candicates
  - We try the `std::string_view::string_view(Range&&)` candicate
    - We meet a `atomic constraint value changes` error. 
    - When we meet this error, should we:
      - A) only stop this candicate, and still continue to try others?
      - B) panic this error globally and aborts all the rest candicates, abort
everything?

I wonder the standard here, as both clang++ and msvc seems to adapt the A) but
gcc seems to adapt the B).
  • [Bug c++/121646] New: `Substitu... shyeyian at petalmail dot com via Gcc-bugs

Reply via email to