<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/62943>62943</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [c++20][Modules] incorrect error regarding ambiguous specialization
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:frontend,
            clang:modules
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
            ChuanqiXu9
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          mordante
      </td>
    </tr>
</table>

<pre>
    Tested with a recent clang nightly build, using libc++'s `std` module.

https://github.com/llvm/llvm-project/blob/11ea40cff5413057d823a4b3ac5ac419b674dc56/libcxx/include/__iterator/readable_traits.h#L84
```
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.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzEWF1z6jYQ_TXiRQNjJJuPBx6IE6aZad_uTPvmkaUF1MqSK8kJ9Nd3ZBvzETuXJPe2M4RgZJ09e_YYe5c5J3caYIWSB0RIuq-Y_lv-US0RISh5HLHK741dFcYKpj2MciOOq2_gPAj8Kv0eM2yBg_aYK6Z3WMvd3qsjziupBCIprpzUO6xkzhF5qF9zh9Escl6gWYQLIyoFExQ9omjdvO-9Lx2ia0Q2iGx20u-rfMJNgchGqZfTv3FpzZ_APSKbXJkckc10CiyO-HabxFMaJXOxIJTFOWU8YTyeLvPZPBY8mQUAmfPDAZGN1FxVAhDZZJn0YJk3FpGNBSZYriDzlknvJntE6K-LuGU5i9pXfeihKBXzgBFNuWLO4ey5RPSpWW3SD9DZC1MVZB4j-oj9sQTNCsDcaCG9NJqpzCOaZpl0WWllwewxO0Ejmp7ItYwQTS0U5gUy_mJh22ytw-L2LwhI13VMRNKGDJZaSAvcq2N2k-L7gBcIX-CRhawRfeiVsXn_BSxgv4fgkHfIziLMWeXAYaYxK3K5q0zlsCuBS6bkPywoisFaY7HUNeDWKGVeQzG4ERBY9bGQRWmsx8GcHc-BKj_7rsjNF9xo3xDprITRvEXB-Nlj6bMOtqxyJXnHA9eWELBtYgfNevAyz3bnEnDmYWfsscM8g3T-6tDeFq5J4KY8uKdSn4YVcrsFC5q32DfHPQGePS6N1B7s16NbaIPh7tNdoK2hOx6XmHUaoKAA7W_s3OJyo52HQ2lDLjlzgMgCkWXzffADtuArq1szYDR_HALoMUALhui63t8ezR86lIvtcCiV5NIP4NR-vAZrjy_g3oCeRTXlCWo9lCIi69ssL_NrFe6QxvUvzX1q4fc5JQ8oeURkcetAPQiePOiw5RMVmV1I0dzhuqq0ABg3K5fXf_j2LJPfS3de6s3yO7HH47644_FVzKGAd0d8m6rUJ9Oc0PvtVjus2bMcrOR7EesEPxAtnL_8ej3poI2uhJY-w83pWP9Ava8q_BEu4xsm97ltayVo8RELLPrOOIQHv-_zPPQoduZ56JfrExR7mKS92w7_A8XxVzUcrvS99G6j3EWtb-F4c20eJrUV8XEydLN7wyU3Rp3LRx8bzze_2APXx4nO8BnHN7JdEWzCdCzvkeyaJpn-DJrXHOsYX-BI0x9H8Fa-tKfC9xD6T2qbflG3p5-n29OndHv6-WarYwyLFj5cP_c2bW7ahXoOz3UBoy86TRtm9c18XQe7Amsafwya5SrAhtsVRoRs5QEcIqTu56RzVTc3qDc4z7zkGXMOrEdk0T3QO1ZAxkJ3cG4c3muEt8qwjtlN90pS3CwHXyw74oOx-_O_FuoG66Yl_RayDz0rlg5bEBUHgbfWFKc-2TK9A9d2XMyz0B17cH6CvwWdwiM2OB-ELJn1AeV1D_q-Lls6XDkQoYlmzdTmMs9ZhLfGhh680hZCeyzwSSV_ilFT56YopQI3wfj3sND4xXepvUq_N5Vvx0EOS49fjf3LYW_MZCRWVCzpko1gNZ0tkoguFzEd7VdCJNE2ingex0si5tMl5XOI43yazISY59ORXJGI0CghyXRB54ROEkgivkimhCU0jmGJ4ggKJtVEqZdiYuxuVPtqNSPLmI4Uy0G5djRWz7cQXW-t0R60QIQgkl4stNzbwZld1VOqvNo5FEdKOu_OQbz0qh65tUMxEoXeI3n4rYVIHrHU3NhQmHaMYWHHrAiqDc07RpVVqw8Pz-p8HSKbOuV_AwAA__-tiXES">