Skip to content

[c++20][Modules] incorrect error regarding ambiguous specialization #62943

Closed
@mordante

Description

@mordante

Tested with a recent Clang nightly build, using libc++'s std module.

using iter_value_t = typename conditional_t<__is_primary_template<iterator_traits<remove_cvref_t<_Ip> > >::value,

template <class _Ip>
using iter_value_t = typename conditional_t<__is_primary_template<iterator_traits<remove_cvref_t<_Ip> > >::value,
                                            indirectly_readable_traits<remove_cvref_t<_Ip> >,
                                            iterator_traits<remove_cvref_t<_Ip> > >::value_type;

Here the indirectly_readable_traits causes an ambiguous specialization error in the following code:

import std;

template <class It>
class contiguous_iterator {
  It it_;
public:
  typedef std::contiguous_iterator_tag iterator_category;
  typedef typename std::iterator_traits<It>::value_type value_type;
  typedef typename std::iterator_traits<It>::difference_type difference_type;
  typedef It pointer;
  typedef typename std::iterator_traits<It>::reference reference;
  typedef typename std::remove_pointer<It>::type element_type;

  constexpr It base() const { return it_; }

  constexpr contiguous_iterator() : it_() {}
  constexpr explicit contiguous_iterator(It it) : it_(it) {}

  constexpr reference operator*() const { return *it_; }
  constexpr pointer operator->() const { return it_; }
  constexpr reference operator[](difference_type n) const { return it_[n]; }

  constexpr contiguous_iterator& operator++() {
    ++it_;
    return *this;
  }
  constexpr contiguous_iterator& operator--() {
    --it_;
    return *this;
  }
  constexpr contiguous_iterator operator++(int) { return contiguous_iterator(it_++); }
  constexpr contiguous_iterator operator--(int) { return contiguous_iterator(it_--); }

  constexpr contiguous_iterator& operator+=(difference_type n) {
    it_ += n;
    return *this;
  }
  constexpr contiguous_iterator& operator-=(difference_type n) {
    it_ -= n;
    return *this;
  }
  friend constexpr contiguous_iterator operator+(contiguous_iterator x, difference_type n) {
    x += n;
    return x;
  }
  friend constexpr contiguous_iterator operator+(difference_type n, contiguous_iterator x) {
    x += n;
    return x;
  }
  friend constexpr contiguous_iterator operator-(contiguous_iterator x, difference_type n) {
    x -= n;
    return x;
  }
  friend constexpr difference_type operator-(contiguous_iterator x, contiguous_iterator y) { return x.it_ - y.it_; }

  friend constexpr bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {
    return x.it_ == y.it_;
  }
  friend constexpr bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {
    return x.it_ != y.it_;
  }
  friend constexpr bool operator<(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ < y.it_; }
  friend constexpr bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {
    return x.it_ <= y.it_;
  }
  friend constexpr bool operator>(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ > y.it_; }
  friend constexpr bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {
    return x.it_ >= y.it_;
  }
};

using ContiguousIter = contiguous_iterator<const int*>;

// enabling this "fixes" the issue.
//static_assert(std::same_as<std::indirectly_readable_traits<float*>::value_type, float>);
static_assert(std::contiguous_iterator<ContiguousIter>);

This code is reduced from the ranges::data test. The interesting part is when the indirectly_readable_traits is used in a static_assert for an unrelated type, then the code compiles. When using this code without modules it works too.

Metadata

Metadata

Assignees

Labels

clang:frontendLanguage frontend issues, e.g. anything involving "Sema"clang:modulesC++20 modules and Clang Header Modules

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions