Fznamznon added inline comments.

================
Comment at: clang/test/SemaCXX/overloaded-operator-decl.cpp:64
+class E {};
+void operator+(E, ...) {} // expected-error{{overloaded 'operator+' cannot be 
variadic}}
+void d() { E() + E(); }
----------------
cor3ntin wrote:
> aaron.ballman wrote:
> > cor3ntin wrote:
> > > aaron.ballman wrote:
> > > > Fznamznon wrote:
> > > > > aaron.ballman wrote:
> > > > > > I think it might make sense to extend the test coverage for the 
> > > > > > other operators you can overload, just to demonstrate we diagnose 
> > > > > > them all consistently. WDYT?
> > > > > Okay, while trying to add more test cases I discovered that following
> > > > > ```
> > > > > class E {};
> > > > > bool operator<(const E& lhs, ...);
> > > > > auto operator<=>(const E& lhs, ...);
> > > > > 
> > > > > void d() {
> > > > >   E() < E();
> > > > > }
> > > > > ```
> > > > > crashes even with the patch since there is code searching for best 
> > > > > overload candidate that doesn't consider possibility for them making 
> > > > > variadic.
> > > > > The code around overloading is actually pretty inconsistent, 
> > > > > somewhere invalid candidates are considered, and somewhere not, so I 
> > > > > spent some time not knowing what to do.
> > > > > I'm now inclined that we just shouldn't consider invalid candidates 
> > > > > like @shafik 
> > > > > suggests. WDYY?
> > > > > 
> > > > Overload resolution doesn't need to produce a candidate that's viable 
> > > > to call; C++ lets you resolve to the "best viable function" only to say 
> > > > "and that one wasn't good enough either." e.g., 
> > > > http://eel.is/c++draft/over#match.general-3
> > > > 
> > > > I've not yet spotted anything in http://eel.is/c++draft/over that says 
> > > > invalid declarations should/should not be added to the initial 
> > > > candidate set. I *think* the intention is that if name lookup can find 
> > > > the name, it goes into the candidate set. Then that set is processed to 
> > > > remove functions that are not viable 
> > > > (http://eel.is/c++draft/over.match.viable). Then we find the best 
> > > > viable function from that set.
> > > > 
> > > > I think we should be keeping the function in the candidate set so long 
> > > > as it matches the rules in http://eel.is/c++draft/over.match.viable 
> > > > even if the function is otherwise not viable. Otherwise, correcting an 
> > > > unrelated issue might change overload resolution to find a completely 
> > > > different function. e.g., in my example above, we'd select `void 
> > > > overloaded(int);` as the best viable function, but when the user 
> > > > corrects the `float` function, we'd change to call that instead. I 
> > > > think it's easier to understand what's going on when picking the 
> > > > `float` overload to begin with and saying "but we can't call that 
> > > > because it's busted".
> > > > 
> > > > CC @cor3ntin @hubert.reinterpretcast @rsmith for some extra opinions, 
> > > > as I'm not certain if I'm interpreting the standard correctly or not.
> > > I'm not sure how much the standardese matter here as the declaration of 
> > > the operators are ill-formed anyway.
> > > But from a QOI perspective, i think keeping in the set everything the 
> > > users might reasonably expect to be considered makes sense to me, as it 
> > > *should* lead to better diagnostics
> > Thanks for the extra perspective! Yeah, I think that's what I've been 
> > convincing myself of. Effectively:
> > ```
> > int overloaded(int);
> > float overloaded(float) noexcept(error()); // error: invalid declaration
> > 
> > int main() {
> >   (void)overloaded(1.0f); // #1
> > }
> > ```
> > We're always going to get the invalid declaration diagnostic. The question 
> > is whether we want a diagnostic at #1 that says "can't call this overload" 
> > or whether we want #1 to have no diagnostic (because it picked the `int` 
> > overload). From a purely diagnostic perspective, I think I can see 
> > arguments either way. But if we change it slightly:
> > ```
> > template <typename Ty>
> > constexpr int func() { return 0; }
> > 
> > template <>
> > constexpr int func<int>() { return 1; }
> > 
> > template <>
> > constexpr int func<float>() { return 2; }
> > 
> > int overloaded(int);
> > float overloaded(float) noexcept(error()); // error: invalid declaration
> > 
> > static_assert(func(overloaded(1.0f)) == 2); // #1
> > ```
> > we still get the invalid declaration diagnostic, but now we get a failing 
> > static assertion because we picked the `int` overload rather than the 
> > `float` overload. I think this is clearly worse behavior than if we issued 
> > an additional diagnostic at #1 saying that the overload we picked (`float`) 
> > was invalid.
> > 
> > https://godbolt.org/z/34aGMY43n
> > 
> > WDYT?
> Agreed. If i write an overload i presumably want the compiler to consider it, 
> even if I botched it. And apparently, the issue is not that we don't do that 
> but rather than we don't always do that. We should strive to be consistent.
> 
> It's not critical because even in the `static_assert` case, the only thing a 
> user can do is fix the declaration, at which point they would get the 
> ambiguity diag or the correct best match correctly picked. But it's nicer to 
> have more diags, when we can
I see, thank you both for the extensive explanation.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156244/new/

https://reviews.llvm.org/D156244

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to