This is an archive of the discontinued LLVM Phabricator instance.

[Sema] Improve overload resolution
Needs ReviewPublic

Authored by Mordante on Sep 12 2020, 10:09 AM.

Details

Reviewers
lvoufo
rsmith
Summary

The overload resolution for initializer lists was incomplete. It did not
properly take the number of elements in the target array into account. The
size comparison already allows for an array of unknown boud, per P0338 'Permit
conversions to arrays of unknown bound'. However currently this is dead code.

This fixes the overload resolution for cases like:

void f(int(&&)[2]);

void g() {
  f({1});
  f({1, 2});
  f({1, 2, 3});
}

The patch adds extra members to ImplicitConversionSequence, making it larger
for members only used for an initializer list. The largest member of the class'
union is UserDefinedConversion. An initializer list can be used with a user
defined conversion sequence, so it's not possible to use unused space in the
union. I'm open to suggestions how to avoid the enlargement of the class.

Diff Detail

Event Timeline

Mordante requested review of this revision.Sep 12 2020, 10:09 AM
Mordante created this revision.

Looks like this is an implementation of DR1307. Please also add a test to test/CXX/drs/dr13xx.cpp.

clang/include/clang/Sema/Overload.h
548–549

Storing the IntListExpr here doesn't seem like it captures the necessary information. Consider:

void f2(std::pair<const char*, const char*> (&&)[]); // #1
void f2(std::string (&&)[]); // #2
void g2() { f2({"foo","bar"}); } // should call #2

Here, the InitListExpr in both cases has two elements. We don't store the converted InitListExpr, because we don't -- and aren't allowed to -- build the converted InitListExpr until we've chosen the right overload. But I think what we're supposed to do in this case is to notice that calling #1 would initialize only one element of the array (one pair), whereas calling #2 would initialize two elements of the array, so we should call #2 here.

In effect, what you need to do is to compute the effective array bound for the case where we're initializing an array of unknown bound, and prefer the conversion sequence with the lower effective array bound. InitListChecker already works this out internally, see here, but currently only does that when actually doing the conversion (when not in VerifyOnly mode); you'd need to adjust that.

Given that the code that needs this (the P0388 part) is dead code for now, perhaps the best thing would be to do only the array bound comparison in this patch, and we can compute the proper array bound for said comparison in a future patch.

clang/lib/Sema/SemaOverload.cpp
3690–3703

I think this would be simpler if structured a little differently:

  • Rename CompareListInitializationSequences::Conversion to ListInitializationSequence.
  • Make CompareListInitializationSequences::Compare a static member of ListInitializationSequence.
  • Move the element type comparison into ...::Compare and remove the CompareListInitializationSequences class, inlining the (now very simple) constructor into its only user.
3856–3861

Should this be part of CompareListInitializationSequences too?

5150–5156

Simplify, and we may as well avoid assuming that the size fits in 64 bits since it's easy to do so here (even though there are lots of other places where we make that assumption).

Mordante added inline comments.Nov 1 2020, 4:41 AM
clang/include/clang/Sema/Overload.h
548–549

I've removed the unused code for P0338 for now. Instead of storing the InitListExpr I've stored the size difference between the array and the initializer list.

Mordante updated this revision to Diff 302140.Nov 1 2020, 4:46 AM
  • No longer store the InitListExpr instead store the size difference between the array and initializer list.
  • Removed the dead code for P0388.
  • Don't add overloads where the initializer list has more elements than the array to be initialized.
  • Since the size validation is simpler now it's directly in CompareImplicitConversionSequences instead of the helper class CompareListInitializationSequences.