This is an archive of the discontinued LLVM Phabricator instance.

[Concepts] Fix Concepts on generic lambda in a VarTemplateSpecDecl
ClosedPublic

Authored by erichkeane on Sep 29 2022, 6:11 AM.

Details

Summary

As fallout of the Deferred Concept Instantiation patch (babdef27c5), we
got a number of reports of a regression, where we asserted when
instantiating a constraint on a generic lambda inside of a variable
template. See: https://github.com/llvm/llvm-project/issues/57958

The problem was that getTemplateInstantiationArgs function only walked
up declaration contexts, and missed that this is not necessarily the
case with a lambda (which can ALSO be in a separate context).

This patch refactors the getTemplateInstantiationArgs function in a way
that is hopefully more readable, and fixes the problem with the concepts
on a generic lambda.

Diff Detail

Event Timeline

erichkeane created this revision.Sep 29 2022, 6:11 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 29 2022, 6:11 AM
erichkeane requested review of this revision.Sep 29 2022, 6:11 AM
erichkeane added inline comments.Sep 29 2022, 12:19 PM
clang/test/SemaTemplate/concepts-lambda.cpp
26

Huh... this f2 example seems to ICE for some reason, I could swear it worked, but building a different patch on top of this one showed me this fails.

Looking into it now, but it isn't critical to this patch, so if the rest looks good, I might remove this test case and fix it in a followup.

Looks like that problem was fixed easy enough, so back to all tests passing :)

I made mostly minor comments, the diff is difficult to follow wrt to what has really changed but it mostly makes sense. I will probably need a second look.

clang/lib/Sema/SemaConcept.cpp
507–511
584–587
1071–1074
clang/lib/Sema/SemaTemplate.cpp
6105–6108
clang/lib/Sema/SemaTemplateDeduction.cpp
2878–2881
clang/lib/Sema/SemaTemplateInstantiate.cpp
48

Maybe put both bool fields back to back.

255–258

This read a little awkward.

Maybe something more like "When collecting arguments ForContraintInstantion indicates that we should..."

264

Dead code?

271–291

Should we assert on ND?

300

This reads weird, my instant is that this should flip to the opposite value when this is true. Maybe an enum with names like RelativeToPrimayOff or something more explicit like that.

erichkeane marked 10 inline comments as done.

Did @shafik s suggestions. And yes, most of the work is just copy/pasted with slight changes to work in the new refactor, which does make it tougher to read, sorry about that :(

The refactoring looks like a good improvement to me. I think there may be some opportunities to make it more robust. I did some spot checking that previous behavior is retained, but didn't exhaustively do such checking; it does look like many of the changes were mechanical bus as Shafik noted, it is a bit difficult to review.

clang/lib/Sema/SemaConcept.cpp
510

This would previously have passed true for LookBeyondLambda and false for IncludeContainingStruct. The merge of both parameters to ForConstraintInstantiation makes that no longer possible. I don't know if that is a good thing or not. Perhaps this was a latent bug?

1067

This would previously have passed true for LookBeyondLambda and false for IncludeContainingStruct. The merge of both parameters to ForConstraintInstantiation makes that no longer possible. I don't know if that is a good thing or not. Perhaps this was a latent bug?

clang/lib/Sema/SemaTemplateDeduction.cpp
2881

This would previously have passed true for LookBeyondLambda and false for IncludeContainingStruct. The merge of both parameters to ForConstraintInstantiation makes that no longer possible. I don't know if that is a good thing or not. Perhaps this was a latent bug?

clang/lib/Sema/SemaTemplateInstantiate.cpp
48

Suggestion: rename RelativeToPrimaryOff to ClearRelativeToPrimary or SetRelativeToPrimaryFalse.

239
242–243

Tangent: When I was investigating this function a while back, I was uncertain what purpose Innermost serves and I didn't find the comment helpful. It appears that there is exactly one call to getTemplateInstantiationArgs() that passes a non-null value for it. That occurs in Sema::CheckTemplateArgumentList() and happens because a template is passed as ND and, while template arguments have been identified, a specialization has not yet been formed, so those arguments are passed for Innermost.

I suggest updating the comment:

/// \param Innermost if non-NULL, specifies a template argument list for the template
/// declaration passed as \p ND.

Perhaps it is worth adding an assert that, if Innermost is non-null, that ND corresponds to a template declaration (not a specialization).

251
296
302–305

This seems a little fragile. How about rolling the else case into the main if/else chain above so that R.NextDecl is always set? We could then assert on it. I added an illustrative suggested edit above. This would require changing a number of the handlers to set NextDecl where they currently don't, but being explicit about the decl navigation in those cases might make the flow easier to understand.

erichkeane marked 9 inline comments as done.Sep 30 2022, 11:21 AM
erichkeane added inline comments.
clang/lib/Sema/SemaConcept.cpp
510

Yeah, I think it was. At the time I put the 2 parameters in, I did a "only set it if I find a place that it NEEDS it". Thinking further through, I can't think of ANY reason these two needed to be different.

I ran this patch against all my workloads I have (like libcxx), and none changed behavior.

1067

Same answer as above.

clang/lib/Sema/SemaTemplateDeduction.cpp
2881

same :)

clang/lib/Sema/SemaTemplateInstantiate.cpp
255–258

Made another run at it.

302–305

Hrm... an interesting idea. I've got a patch that I'm cleaning up to do this that I think will end up handling this alright. The only awkward is the DontClearRelativeToPrimary function.

I CONSIDERED doing a 'builder' pattern for Response, but that doesn't try very hard to statically enforce what we're hoping for here. BUT, let me know what you think of what I have.

erichkeane marked 4 inline comments as done.

Do all the things Tom requested.

I can confirm that, with this patch, Clang successfully compiles my actual code base.

tahonermann accepted this revision.Oct 3 2022, 12:13 PM

I think this looks good. I took more time to compare with the current code and it looks to me like behavioral consistency is maintained where desired.

I added one comments requesting a change to a comment (to be made when committing the changes) and another comment with a question asked to improve my own understanding (that might also indicate that some additional comments would be helpful).

clang/lib/Sema/SemaTemplateInstantiate.cpp
75–77

I think the selected portion of this comment would be better placed inside the function before the call to isClassScopeExplicitSpecialization.

255–259

More a question than a review comment: why is ForConstraintInstantiation needed? The behavior it enables seems to me like the behavior that would always be desired. When would template arguments for such enclosing templates not be wanted?

This revision is now accepted and ready to land.Oct 3 2022, 12:13 PM
erichkeane added inline comments.Oct 3 2022, 12:28 PM
clang/lib/Sema/SemaTemplateInstantiate.cpp
255–259

Apparently we DONT always want the full depth. It is the intent to only get as far back as 'needed' in some cases, and ForConstraintInstantiation causes us to go 'all the way to the TU' as far as I can tell. TBH, I'm not super clear on it. I tried at one point just modifying it, and it broke a ton of tests.

This revision was landed with ongoing or failed builds.Oct 3 2022, 12:44 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptOct 3 2022, 12:44 PM
tahonermann added inline comments.Oct 3 2022, 12:48 PM
clang/lib/Sema/SemaTemplateInstantiate.cpp
255–259

Ok, thanks. My guess is that implies bugs elsewhere but that isn't a concern for this change!