This is an archive of the discontinued LLVM Phabricator instance.

DR2303: Prefer 'nearer' base classes during template deduction.
ClosedPublic

Authored by erichkeane on Jul 17 2020, 9:53 AM.

Details

Summary

DR2303 fixes the case where the derived-base match for template
deduction is ambiguous if a base-of-base ALSO matches. The canonical
example (as shown in the test) is just like the MSVC implementation of
std::tuple.

This fixes a fairly sizable issue, where if a user inherits from
std::tuple on Windows (with the MS STL), they cannot use that type to
call a function that takes std::tuple.

Diff Detail

Event Timeline

erichkeane created this revision.Jul 17 2020, 9:53 AM

I added @rsmith directly, since I suspect he's the most knowledgeable in SemaTemplateDeduction.cpp, but if anyone knows of someone else who is a good fit for this review, please add them as well!

Woops, left in a TODO from when I was planning on how to do this patch. Should be ready now :)

aaron.ballman added a subscriber: aaron.ballman.

While this looks reasonable to me, I don't feel comfortable signing off on it because Templates Are Complicated (switching myself to a subscriber instead).

Also make sure to update the the cxx_dr_status.html document.

Additionally, I sent out a CWG message on the reflector about this: https://godbolt.org/z/bEr61T

My implementation has this as ambiguous, but the wording makes it well-formed I think. I don't think that was the intent of CWG2303, so unless they confirm that this was their intent (or that I'm wrong), I'll leave this patch as is.

riccibruno added a comment.EditedJul 21 2020, 12:19 PM

Also make sure to update the the cxx_dr_status.html document.

It is auto-generated. You need to tag the test case: dr2303: 12.

Edit: And put it at the right place in the file (not at the end).

Also make sure to update the the cxx_dr_status.html document.

It is auto-generated. You need to tag the test case: dr2303: 12.

Edit: And put it at the right place in the file (not at the end).

Do you have an example of this? I've not seen that anywhere before.

Also make sure to update the the cxx_dr_status.html document.

It is auto-generated. You need to tag the test case: dr2303: 12.

Edit: And put it at the right place in the file (not at the end).

Do you have an example of this? I've not seen that anywhere before.

Ah, doh, I see a few now. Is that number the compiler version number?

Also make sure to update the the cxx_dr_status.html document.

It is auto-generated. You need to tag the test case: dr2303: 12.

Edit: And put it at the right place in the file (not at the end).

Do you have an example of this? I've not seen that anywhere before.

The test-case just above namespace dr2387 { // dr2387: 9.

riccibruno added a comment.EditedJul 21 2020, 12:23 PM

Ah, doh, I see a few now. Is that number the compiler version number?

Yup

Revert change to cxx_dr_status and update the test to have the right tag.

Additionally, I sent out a CWG message on the reflector about this: https://godbolt.org/z/bEr61T

My implementation has this as ambiguous, but the wording makes it well-formed I think. I don't think that was the intent of CWG2303, so unless they confirm that this was their intent (or that I'm wrong), I'll leave this patch as is.

Let's wait to hear back. Either option seems plausible here. The wording as written behaves the same way as name shadowing in member name lookup, so it may be intentional.

clang/test/CXX/drs/dr23xx.cpp
118

This should include a comment that make_cxx_dr_status can parse, such as // dr2303: 11 to indicate support in Clang 11 onwards.

clang/www/cxx_dr_status.html
13636

This is a generated file; use make_cxx_dr_status in the same directory to regenerate it.

erichkeane marked 2 inline comments as done.Jul 21 2020, 12:54 PM

I'd attempted to regenerate the cxx_dr_status.html using make_cxx_dr_status, but I get a 'no such

Additionally, I sent out a CWG message on the reflector about this: https://godbolt.org/z/bEr61T

My implementation has this as ambiguous, but the wording makes it well-formed I think. I don't think that was the intent of CWG2303, so unless they confirm that this was their intent (or that I'm wrong), I'll leave this patch as is.

Let's wait to hear back. Either option seems plausible here. The wording as written behaves the same way as name shadowing in member name lookup, so it may be intentional.

Agreed. I think the pruning mechanism as implemented here is superior for a few reasons (and is easier to reason about mentally), but I want to see what CWG has to say.

FWIW, I though of the problem with this patch AFTER the fact (or at least, completely understood the wording at that point), so I wasn't aware of it when I wrote this patch.

clang/test/CXX/drs/dr23xx.cpp
118

Our current clang-version is 12.0.0, so 12 is correct here, right?

I've not been able to get make_cxx_dr_status work unfortunately. It seems to generate a blank version of the file (well, it HAS html, but none of the content).

I used the cwg_index.html from here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_index.html

erichkeane marked an inline comment as done.

As CWG seems unmoved by my argument as to why CWG2303 should change, I've opted to implement it as worded. As you can see, the implementation is somewhat more complicated, but I believe I made it at least reasonably understandable.

I've also now updated the cwg_dr_status.html file via the script, which I also updated to acknowledge the current released version.

rsmith added inline comments.Jul 22 2020, 4:32 PM
clang/lib/Sema/SemaTemplateDeduction.cpp
1204–1205

Missing ///

1281

It would be better to add the class to Visited here rather than in the loop below -- that is, only add each class to ToVisit once rather than only processing each class once. That would put a tighter upper bound on the size of ToVisit.

1329–1331

This deduction step seems unnecessary to me (whether deduction succeeds or not here has no impact on the result of the algorithm).

Instead, you could perform the erase_if call below unconditionally. In order for that to be efficient, it'd make sense to also convert Matches into a hash map from (canonical) CXXRecordDecl* to BaseMatch.

1333

Typo "iS".

1351–1353

These fields are used to determine how to diagnose a deduction failure, and don't mean anything if deduction succeeds. I think this (and the tracking of BaseInfo above) is all dead code (and the corresponding code was similarly dead prior to this change).

clang/test/CXX/drs/dr23xx.cpp
118

Oh, right, version 11 already forked. How time flies =) Yes, 12 is correct.

The current list is built from revision 101m of the core issues list. You'll need to grab that from the WG21 wiki; there hasn't been a public release of the core issues list in over 2 years. (Though it looks like you got this working anyway?)

clang/www/cxx_dr_status.html
1507

Please commit the update from "unreleased" to "full" for Clang 11 changes separately.

erichkeane marked 5 inline comments as done.Jul 22 2020, 4:45 PM

Thanks for the review! I'll get this updated in the morning. I DO have a question on your suggestion for the ToVisit/Visited example, so if you could explain a little better, I'd be grateful.

clang/lib/Sema/SemaTemplateDeduction.cpp
1281

I'm perhaps missing something here... Can you clarify your suggestion a bit more? If we add it to 'Visited' here, it will never get visited in the while-loop below, right?

1329–1331

Ah, yes, thats a really good observation! I'll do that.

1351–1353

I see, so all tracking of BaseInfo isn't useful? That will simplify the code quite a bit then, since BaseInfo accounts for nearly all the code in BaseMatch (both the move operations, and the constructor only exist because of it). BaseMatch becomes essentially a pair otherwise. I think I can actually remove BaseMatch entirely as a result, and change the Matches to a map from RecordType* to the SmallVector of Deduction state.

clang/test/CXX/drs/dr23xx.cpp
118

Yep, I figured that out with help from @aaron.ballman on IRC :) I downloaded 101m from the wiki.

clang/www/cxx_dr_status.html
1507

Will do! I'll do that as review-after-commit, then rebase this on top of it. Thanks!

rsmith added inline comments.Jul 22 2020, 6:47 PM
clang/lib/Sema/SemaTemplateDeduction.cpp
1281

The idea would be to remove the Visited check in the loops below. We would guarantee that each class is only visited once by only adding it to ToVisit once. (As an example, we do the same thing for Queue and Visited here: https://github.com/llvm/llvm-project/blob/master/clang/lib/Sema/SemaLookup.cpp#L1992)

erichkeane marked 9 inline comments as done.

Fix all the things that @rsmith suggested.

Thanks for the feedback, it is looking much better!

I ended up using a MapVector instead of std::map for the RecordType*->SmallVector map, since we iterate over it. While the iteration SHOULDN'T matter (it is just the order that bases are added), if there is any bug/unconsidered situation, we might diagnose in a non-deterministic manner. Let me know if I'm being overly concerned there and I can switch it to std::map (DenseMap ends up being a bad choice according to the docs).

Ping! I believe I've done all of the requested changes.

rsmith accepted this revision.Jul 30 2020, 4:00 PM

Thanks, looks nice =)

clang/lib/Sema/SemaTemplateDeduction.cpp
1205
1207–1217
This revision is now accepted and ready to land.Jul 30 2020, 4:00 PM
erichkeane marked 2 inline comments as done.Jul 30 2020, 4:42 PM

Thanks! I'm done for the day, so I'll push in the morning when I'll have a few hours to respond to build bots.

Thanks again!

Herald added a project: Restricted Project. · View Herald TranscriptJul 31 2020, 5:40 AM