Is this a bug?

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Is this a bug?

Alex Denisov via cfe-dev
In our code base, we have the following (code linked below):

* A class template for "handles" to objects of assorted types, 
  Handle<T, Policy>; T is the actual element type
* Handle contains a member operator < (and others). It uses the 
  "address" of the object to do the comparison.
* There is a special class where we want to customize operator < 
  so it looks into the associated object, so we have a templated 
  overload free function of operator< on Handle<Special, T2>.

I've got my doubts as to the sanity of this design in some ways, but I don't think I can reasonably change it.

This compiles with GCC [1], and with MSVC [2], but Clang gives an error about the two operator<s being ambiguous, starting with 3.5 [3].

Perhaps importantly, the operator< member of Handle has this "signature":

   template <typename T, typename Policy>
   template <typename RHS_Handle>
   bool Handle<T, Policy>::operator< (RHS_Handle const &)

and the free function has this signature:

    template <
        typename LHS_T, typename LHS_Policy,
        typename RHS_T, typename RHS_Policy>
    bool operator<  (
        Handle<LHS_T, LHS_Policy> lhs,
        Handle<RHS_T, RHS_Policy> rhs);

At least if we ignore the references and cv-quals, my understanding is that the latter function should have priority over the former because it's more specialized -- the second parameter is Handle<RHS_T, RHS_Policy> rather than a generic RHS_Handle type.

So if the function is called with 

    Handle<MyType, SomePolicy> h1, h2;
    h1 < h2;

then it should not be ambiguous, and select the free overload. However, perhaps the cv-qualification matters, and GCC/MSVC get it wrong?

Credit to OmegaNaughtEquals1 on Reddit who pointed me to some standards text that seems to support the position that it should work (maybe... it's too late to really tell what should be happening with the cv/ref stuff) [4].

If I change the free function to take 'lhs' by reference, then Clang compiles it [5].

I'm happy to report this to the bug tracker if that's what I should do -- I just wasn't sure if I should with something that I'm not sure is a bug.

Thanks,
Evan

[1] GCC compiles it: https://godbolt.org/g/9EaoYh
[2] MSVC does too: https://godbolt.org/g/ubXeC3
[3] Clang's error: https://godbolt.org/g/MhNEky
[5] Modified copy with ref parameter: https://godbolt.org/g/v9HtuH

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Is this a bug?

Alex Denisov via cfe-dev
Converting your case:
template <typename T, typename Policy>
struct Handle
{
  template <typename Rhs> bool operator <(Rhs rhs) const;
};

struct Special;

template <typename LHS_T2, typename RHS_T2>
bool operator <(Handle<Special, LHS_T2> lhs, Handle<Special, RHS_T2> rhs);

bool f() {
  Handle<Special, int> h1, h2;
  return h1 < h2;
}

to

template <typename T, typename Policy> struct Handle { };
struct Special;

template <typename Rhs>
bool operator <(const Handle<Special, int> &, Rhs);

template <typename LHS_T2, typename RHS_T2>
bool operator <(Handle<Special, LHS_T2>, Handle<Special, RHS_T2>);

bool f() {
  Handle<Special, int> h1, h2;
  return h1 < h2;
}

Gives the same behaviour between Clang and GCC.

On Sun, Dec 10, 2017 at 3:11 AM, Evan Driscoll via cfe-dev <[hidden email]> wrote:
In our code base, we have the following (code linked below):

* A class template for "handles" to objects of assorted types, 
  Handle<T, Policy>; T is the actual element type
* Handle contains a member operator < (and others). It uses the 
  "address" of the object to do the comparison.
* There is a special class where we want to customize operator < 
  so it looks into the associated object, so we have a templated 
  overload free function of operator< on Handle<Special, T2>.

I've got my doubts as to the sanity of this design in some ways, but I don't think I can reasonably change it.

This compiles with GCC [1], and with MSVC [2], but Clang gives an error about the two operator<s being ambiguous, starting with 3.5 [3].

Perhaps importantly, the operator< member of Handle has this "signature":

   template <typename T, typename Policy>
   template <typename RHS_Handle>
   bool Handle<T, Policy>::operator< (RHS_Handle const &)

and the free function has this signature:

    template <
        typename LHS_T, typename LHS_Policy,
        typename RHS_T, typename RHS_Policy>
    bool operator<  (
        Handle<LHS_T, LHS_Policy> lhs,
        Handle<RHS_T, RHS_Policy> rhs);

At least if we ignore the references and cv-quals, my understanding is that the latter function should have priority over the former because it's more specialized -- the second parameter is Handle<RHS_T, RHS_Policy> rather than a generic RHS_Handle type.

So if the function is called with 

    Handle<MyType, SomePolicy> h1, h2;
    h1 < h2;

then it should not be ambiguous, and select the free overload. However, perhaps the cv-qualification matters, and GCC/MSVC get it wrong?

Credit to OmegaNaughtEquals1 on Reddit who pointed me to some standards text that seems to support the position that it should work (maybe... it's too late to really tell what should be happening with the cv/ref stuff) [4].

If I change the free function to take 'lhs' by reference, then Clang compiles it [5].

I'm happy to report this to the bug tracker if that's what I should do -- I just wasn't sure if I should with something that I'm not sure is a bug.

Thanks,
Evan

[1] GCC compiles it: https://godbolt.org/g/9EaoYh
[2] MSVC does too: https://godbolt.org/g/ubXeC3
[3] Clang's error: https://godbolt.org/g/MhNEky
[5] Modified copy with ref parameter: https://godbolt.org/g/v9HtuH

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Is this a bug?

Alex Denisov via cfe-dev
GCC does not seem to care enough about the "first parameter":
struct A {
  template <typename T> bool operator<(T &) &; // #1
};

template <typename T> bool operator<(T &, A &); // #2

void g(A *ap) { *ap < *ap; } // GCC picks #2; Clang and MSVC says ambiguous

Given that the constrained and unconstrained parameters are similar in their constrainedness between the two candidates (just with different ordering), and the arguments provided match just as well: it seems to me that what GCC does is broken here.


On Sun, Dec 10, 2017 at 10:05 AM, Hubert Tong <[hidden email]> wrote:
Converting your case:
template <typename T, typename Policy>
struct Handle
{
  template <typename Rhs> bool operator <(Rhs rhs) const;
};

struct Special;

template <typename LHS_T2, typename RHS_T2>
bool operator <(Handle<Special, LHS_T2> lhs, Handle<Special, RHS_T2> rhs);

bool f() {
  Handle<Special, int> h1, h2;
  return h1 < h2;
}

to

template <typename T, typename Policy> struct Handle { };
struct Special;

template <typename Rhs>
bool operator <(const Handle<Special, int> &, Rhs);

template <typename LHS_T2, typename RHS_T2>
bool operator <(Handle<Special, LHS_T2>, Handle<Special, RHS_T2>);

bool f() {
  Handle<Special, int> h1, h2;
  return h1 < h2;
}

Gives the same behaviour between Clang and GCC.

On Sun, Dec 10, 2017 at 3:11 AM, Evan Driscoll via cfe-dev <[hidden email]> wrote:
In our code base, we have the following (code linked below):

* A class template for "handles" to objects of assorted types, 
  Handle<T, Policy>; T is the actual element type
* Handle contains a member operator < (and others). It uses the 
  "address" of the object to do the comparison.
* There is a special class where we want to customize operator < 
  so it looks into the associated object, so we have a templated 
  overload free function of operator< on Handle<Special, T2>.

I've got my doubts as to the sanity of this design in some ways, but I don't think I can reasonably change it.

This compiles with GCC [1], and with MSVC [2], but Clang gives an error about the two operator<s being ambiguous, starting with 3.5 [3].

Perhaps importantly, the operator< member of Handle has this "signature":

   template <typename T, typename Policy>
   template <typename RHS_Handle>
   bool Handle<T, Policy>::operator< (RHS_Handle const &)

and the free function has this signature:

    template <
        typename LHS_T, typename LHS_Policy,
        typename RHS_T, typename RHS_Policy>
    bool operator<  (
        Handle<LHS_T, LHS_Policy> lhs,
        Handle<RHS_T, RHS_Policy> rhs);

At least if we ignore the references and cv-quals, my understanding is that the latter function should have priority over the former because it's more specialized -- the second parameter is Handle<RHS_T, RHS_Policy> rather than a generic RHS_Handle type.

So if the function is called with 

    Handle<MyType, SomePolicy> h1, h2;
    h1 < h2;

then it should not be ambiguous, and select the free overload. However, perhaps the cv-qualification matters, and GCC/MSVC get it wrong?

Credit to OmegaNaughtEquals1 on Reddit who pointed me to some standards text that seems to support the position that it should work (maybe... it's too late to really tell what should be happening with the cv/ref stuff) [4].

If I change the free function to take 'lhs' by reference, then Clang compiles it [5].

I'm happy to report this to the bug tracker if that's what I should do -- I just wasn't sure if I should with something that I'm not sure is a bug.

Thanks,
Evan

[1] GCC compiles it: https://godbolt.org/g/9EaoYh
[2] MSVC does too: https://godbolt.org/g/ubXeC3
[3] Clang's error: https://godbolt.org/g/MhNEky
[5] Modified copy with ref parameter: https://godbolt.org/g/v9HtuH

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Is this a bug?

Alex Denisov via cfe-dev
As for MSVC, it seems it has some sort of off-by-one-error:
struct ty1st;
//typedef ty1st ty2nd;
struct ty2nd;

template <typename TT, typename UU>
struct A {
  template <typename T> void operator<(A<T, ty2nd> &) &;
};

template <typename T> void operator<(A<int, ty1st> &, T &);

void g(A<int, ty1st> *ap, A<void, ty2nd> *a2p) { *ap < *a2p; }

That is, the parameter type for the LHS in the non-member function seems to be matched to that for the RHS in the non-static member function.

On Sun, Dec 10, 2017 at 10:43 PM, Hubert Tong <[hidden email]> wrote:
GCC does not seem to care enough about the "first parameter":
struct A {
  template <typename T> bool operator<(T &) &; // #1
};

template <typename T> bool operator<(T &, A &); // #2

void g(A *ap) { *ap < *ap; } // GCC picks #2; Clang and MSVC says ambiguous

Given that the constrained and unconstrained parameters are similar in their constrainedness between the two candidates (just with different ordering), and the arguments provided match just as well: it seems to me that what GCC does is broken here.


On Sun, Dec 10, 2017 at 10:05 AM, Hubert Tong <[hidden email]> wrote:
Converting your case:
template <typename T, typename Policy>
struct Handle
{
  template <typename Rhs> bool operator <(Rhs rhs) const;
};

struct Special;

template <typename LHS_T2, typename RHS_T2>
bool operator <(Handle<Special, LHS_T2> lhs, Handle<Special, RHS_T2> rhs);

bool f() {
  Handle<Special, int> h1, h2;
  return h1 < h2;
}

to

template <typename T, typename Policy> struct Handle { };
struct Special;

template <typename Rhs>
bool operator <(const Handle<Special, int> &, Rhs);

template <typename LHS_T2, typename RHS_T2>
bool operator <(Handle<Special, LHS_T2>, Handle<Special, RHS_T2>);

bool f() {
  Handle<Special, int> h1, h2;
  return h1 < h2;
}

Gives the same behaviour between Clang and GCC.

On Sun, Dec 10, 2017 at 3:11 AM, Evan Driscoll via cfe-dev <[hidden email]> wrote:
In our code base, we have the following (code linked below):

* A class template for "handles" to objects of assorted types, 
  Handle<T, Policy>; T is the actual element type
* Handle contains a member operator < (and others). It uses the 
  "address" of the object to do the comparison.
* There is a special class where we want to customize operator < 
  so it looks into the associated object, so we have a templated 
  overload free function of operator< on Handle<Special, T2>.

I've got my doubts as to the sanity of this design in some ways, but I don't think I can reasonably change it.

This compiles with GCC [1], and with MSVC [2], but Clang gives an error about the two operator<s being ambiguous, starting with 3.5 [3].

Perhaps importantly, the operator< member of Handle has this "signature":

   template <typename T, typename Policy>
   template <typename RHS_Handle>
   bool Handle<T, Policy>::operator< (RHS_Handle const &)

and the free function has this signature:

    template <
        typename LHS_T, typename LHS_Policy,
        typename RHS_T, typename RHS_Policy>
    bool operator<  (
        Handle<LHS_T, LHS_Policy> lhs,
        Handle<RHS_T, RHS_Policy> rhs);

At least if we ignore the references and cv-quals, my understanding is that the latter function should have priority over the former because it's more specialized -- the second parameter is Handle<RHS_T, RHS_Policy> rather than a generic RHS_Handle type.

So if the function is called with 

    Handle<MyType, SomePolicy> h1, h2;
    h1 < h2;

then it should not be ambiguous, and select the free overload. However, perhaps the cv-qualification matters, and GCC/MSVC get it wrong?

Credit to OmegaNaughtEquals1 on Reddit who pointed me to some standards text that seems to support the position that it should work (maybe... it's too late to really tell what should be happening with the cv/ref stuff) [4].

If I change the free function to take 'lhs' by reference, then Clang compiles it [5].

I'm happy to report this to the bug tracker if that's what I should do -- I just wasn't sure if I should with something that I'm not sure is a bug.

Thanks,
Evan

[1] GCC compiles it: https://godbolt.org/g/9EaoYh
[2] MSVC does too: https://godbolt.org/g/ubXeC3
[3] Clang's error: https://godbolt.org/g/MhNEky
[5] Modified copy with ref parameter: https://godbolt.org/g/v9HtuH

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev





_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev