Apparently valid C++ code rejected as ambiguous

Hi all,
clang 2.8 fails to compile the following code:

template <typename T_type>
class O {
T_type *val;

public:
  O();
  O(T_type); // t

  O(const O& other_value); // copy ctor

  template <typename T_tmp>
  explicit O(const O<T_tmp>& other_value); // other O

  template <typename T_tmp>
  explicit O(const T_tmp& other_value); // other t

  inline bool operator==(const O& other_value) const;

  inline bool operator!=(const O& other_value) const;

  template <typename T_tmp>
  inline bool operator==(const T_tmp& other_value) const; // line 22

  template <typename T_tmp>
  inline bool operator!=(const T_tmp& other_value) const;

};

class C{
public:
  C();
};

class U_C{
public:
  U_C();
  U_C(const U_C&); // copy ctor
  /*explicit*/ U_C(const C&);
};

template<typename T_left, typename T_right>
inline bool operator==(const T_left& left_value, // line 42
  const O<T_right>& right_value)
{ return true; }

template<typename T_left, typename T_right>
inline bool operator!=(const T_left& left_value,
  const O<T_right>& right_value)
{ return false; }

int main()
{
  C cs;
  U_C us;
  O<C> ocs;
  O<U_C> ous;

  if (ocs == ous) {
    return 0;
  }
}
- - - - -
wtf.cc:59:11: error: use of overloaded operator '==' is ambiguous
  if (ocs == ous) {
      ~~~ ^ ~~~
wtf.cc:22:15: note: candidate function [with $0 = O<U_C>]
  inline bool operator==(const T_tmp& other_value) const;
              ^
wtf.cc:42:13: note: candidate function [with T_left = O<C>, T_right = U_C]
inline bool operator==(const T_left& left_value,

The code is accepted by GCC 4.6, the online version of Comeau and even
the online version of LLVM 2.7 !
This appears to be a regression. I had a brief look in Bugzilla but I
didn't spot anything close enough.

If "explicit" is removed from the two constructors, another operator==
(line 17) joins the list of possible candidates (even though GCC
continues to accept it).

Apart from this, it compiled our application (250kloc of C++) with
only a few spurious warnings (and a couple of valid warnings which
were missed by GCC!).
I like the colored error markers :slight_smile:

Regards, Csaba

Hi all,
clang 2.8 fails to compile the following code:

template <typename T_type>
class O {
T_type *val;

public:
O();
O(T_type); // t

O(const O& other_value); // copy ctor

template <typename T_tmp>
explicit O(const O<T_tmp>& other_value); // other O

template <typename T_tmp>
explicit O(const T_tmp& other_value); // other t

inline bool operator==(const O& other_value) const;

inline bool operator!=(const O& other_value) const;

template <typename T_tmp>
inline bool operator==(const T_tmp& other_value) const; // line 22

template <typename T_tmp>
inline bool operator!=(const T_tmp& other_value) const;

};

class C{
public:
C();
};

class U_C{
public:
U_C();
U_C(const U_C&); // copy ctor
/*explicit*/ U_C(const C&);
};

template<typename T_left, typename T_right>
inline bool operator==(const T_left& left_value, // line 42
const O<T_right>& right_value)
{ return true; }

template<typename T_left, typename T_right>
inline bool operator!=(const T_left& left_value,
const O<T_right>& right_value)
{ return false; }

int main()
{
C cs;
U_C us;
O<C> ocs;
O<U_C> ous;

if (ocs == ous) {
   return 0;
}
}
- - - - -
wtf.cc:59:11: error: use of overloaded operator '==' is ambiguous
if (ocs == ous) {
     ~~~ ^ ~~~
wtf.cc:22:15: note: candidate function [with $0 = O<U_C>]
inline bool operator==(const T_tmp& other_value) const;
             ^
wtf.cc:42:13: note: candidate function [with T_left = O<C>, T_right = U_C]
inline bool operator==(const T_left& left_value,

This *might* be related to

  http://llvm.org/bugs/show_bug.cgi?id=8130

but I haven't looked at it closely enough to be sure.

The code is accepted by GCC 4.6, the online version of Comeau and even
the online version of LLVM 2.7 !

The online version of LLVM 2.7 is LLVM-GCC, which is based on GCC 4.2.

This appears to be a regression. I had a brief look in Bugzilla but I
didn't spot anything close enough.

I'm fairly certain that it is not a regression. I looked back quite a ways, and no version of Clang has handled this.

  - Doug

Hi all,
clang 2.8 fails to compile the following code:

(snip)

This *might* be related to

   http://llvm.org/bugs/show_bug.cgi?id=8130

Looks similar indeed. But the bug is marked fixed; my example code is
still not accepted by: clang version 2.9 (trunk 119002)

I'm fairly certain that it is not a regression.

You are right, I got confused between LLVM 2.7 and clang 2.7

It's fixed in Clang r119145, but you should consider a different approach, because this code will only work in C++98/03. If you turn on C++0x mode, it will become ambiguous again.

Essentially, the C++ standard didn't say (until recently!) what happened when performing function template partial ordering between a non-static member function and a free function. That got clarified for C++0x about three months ago:

  C++ Standard Core Language Defect Reports and Accepted Issues

However, the agreed-upon semantics are different than what GCC implements; hence, implementing that DR532 (which was recorded as Clang bug PR8130), left your code broken.

I've gone ahead and made Clang implement GCC's semantics in C++98/03 mode, but the correct C++0x semantics in C++0x mode.

  - Doug