This is an archive of the discontinued LLVM Phabricator instance.

[clang] Fix visitation of ConceptSpecializationExpr in constrained-parameter
ClosedPublic

Authored by nridge on Jul 20 2020, 12:09 AM.

Details

Summary

RecursiveASTVisitor needs to traverse TypeConstraint::ImmediatelyDeclaredConstraint

Diff Detail

Event Timeline

nridge created this revision.Jul 20 2020, 12:09 AM

just some drive-by comments.

clang-tools-extra/clangd/unittests/FindTargetTests.cpp
457

Flags is preserved between EXPECT_DECLS calls, so either use assignment or set it only once at the beginning of the test.

clang/include/clang/AST/ExprConcepts.h
132 ↗(On Diff #279135)

i think we should have some tests in clang, at least an ast-dump test in clang/test/AST/ (for both cases) and possibly also in clang/unittests/AST/SourceLocationTest.cpp

hokein added a subscriber: hokein.Jul 24 2020, 3:02 AM

as you mentioned in the description, there are two problems, I'd prefer address them in two different patches.

clang/include/clang/AST/ExprConcepts.h
132 ↗(On Diff #279135)

+1, ast-dump should be enough to test the invalid end loc, I have a D84461 to slightly improve the dump.

clang/include/clang/AST/RecursiveASTVisitor.h
1780

Looks like we may visit some nodes in ConceptReference twice:

  • getImmediatelyDeclaredConstraint returns a ConceptSpecializationExpr (most cases?) which is a subclass of ConceptReference;
  • TraverseStmt(ConceptSpecializationExpr*) will dispatch to TraverseConceptSpecializationExpr which invokes TraverseConceptReference (see Line 2719);

It is sad that we don't have enough test coverage, could you write some tests in clang/unittests/Tooling/RecursiveASTVisitorTests/?

nridge marked 2 inline comments as done.Jul 26 2020, 5:40 PM
nridge added inline comments.
clang/include/clang/AST/ExprConcepts.h
132 ↗(On Diff #279135)

Will do. By the way, is there something more tailored than ninja check-clang to run these ast-dump tests? ninja check-clang takes quite a while to run...

nridge updated this revision to Diff 280771.Jul 26 2020, 7:58 PM
nridge marked an inline comment as done.

Spun off the source-location issue to D84613.

Some other review comments remain to be addressed.

nridge planned changes to this revision.Jul 26 2020, 7:59 PM
nridge edited the summary of this revision. (Show Details)
nridge marked 2 inline comments as done.Jul 26 2020, 11:35 PM
nridge added inline comments.
clang/include/clang/AST/RecursiveASTVisitor.h
1780

It is true that there will be two calls to TraverseConceptReference(). However, they are called on two different ConceptReference objects:

  • the call in TraverseConceptSpecializationExpr will visit the base subobject of the ConceptSpecializationExpr (which inherits from ConceptReference)
  • the call in TraverseTemplateTypeParmDecl will visit the base subobject of the TypeConstraint (which also inherits from ConceptReference).

So, I think this is fine -- there are two distinct ConceptReference objects in the AST, and with this patch we visit both of them.

nridge updated this revision to Diff 280797.Jul 27 2020, 12:06 AM
nridge marked an inline comment as done.

Finish addressing review comments

nridge marked an inline comment as done.Jul 27 2020, 12:07 AM
nridge added inline comments.
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
435

I'd like to keep this clangd-specific test coverage as I think it's valuable to have. However, I can spin it off into a separate patch if you prefer.

nridge retitled this revision from [clangd] Fix visitation of ConceptSpecializationExpr in constrained-parameter to [clang] Fix visitation of ConceptSpecializationExpr in constrained-parameter.

Will do. By the way, is there something more tailored than ninja check-clang to run these ast-dump tests? ninja check-clang takes quite a while to run...

You can use check-clang-ast for the lit tests in AST/, check-clang-sema for the lit tests in Sema/ and so on. Or you can run an individual test with llvm-lit ~/path/to/the/lit/test.

nridge added a comment.Aug 2 2020, 6:18 PM

(This should be ready for another round of review.)

hokein added a subscriber: rsmith.Aug 3 2020, 4:11 AM
hokein added inline comments.
clang/include/clang/AST/RecursiveASTVisitor.h
1780

I understand that they are two different ConceptReference objects, but they have members (FoundDecl, ArgsAsWritten) that may refer to the same AST nodes.

template <typename T, typename U>
concept binary_concept = true;
struct Foo {};

template<binary_concept<Foo> T> // the template argument Foo will be visited twice.
void k2();

I'm not sure what's is the right approach here, I can see two options:

  • traverse TC + immediately-declared-constraint expr, this seem to cause some ast nodes visited twice (maybe not a big deal?)
  • just traverse immediately-declared-constraint expr, this seems not breaking any tests, but the immediately-declared-constraint expr could be nullptr (e.g. broken code, missing required template arguments); or the immediately-declared-constraint expr could be a CXXFoldExpr, which will make some members in ConceptReference not be visited;

@rsmith, do you have any idea about this?

nridge updated this revision to Diff 282807.Aug 3 2020, 11:55 PM

Rebase on top of D85108

nridge added inline comments.Aug 4 2020, 12:10 AM
clang/include/clang/AST/RecursiveASTVisitor.h
1780

From clangd's point of view, it would be sufficient to visit the immediately-declared-constraint-expr without visiting any of its descendants. However, I'm not sure how to accomplish this using RecursiveASTVisitor. (I think I'd want to call WalkUpFromXXX(TC->getImmediatelyDeclaredConstraint()), where XXX is the dynamic type of the immediately-delcared-constraint, but I don't know how to dispatch to that dynamic type; RecursiveASTVisitor seems to be designed to do the dispatch on Traverse calls, not WalkUpFrom calls).

hokein added inline comments.Aug 10 2020, 7:47 AM
clang/include/clang/AST/RecursiveASTVisitor.h
1780

Thinking more about this.

I'm aligned on the idea of only traversing the immediately declared constraint since the TypeContraint is a wrapper of it. The regression is that we'd not perform traversal if the immediately declared constraint is nullptr (this just happens for broken code).

Fix ideas:

  • build a recovery expression if we can't not build a immediately declared constraint due to the missing required template arguments etc;
  • still traverse the TC if immediately declared constraint is nullptr;
nridge updated this revision to Diff 285910.Aug 16 2020, 4:20 PM

Only visit the TypeConstraint if the immediately-declared-constraint is null

nridge updated this revision to Diff 285911.Aug 16 2020, 4:23 PM

Update test

nridge marked 2 inline comments as done.Aug 16 2020, 4:23 PM
nridge added inline comments.
clang/include/clang/AST/RecursiveASTVisitor.h
1780

Thanks, this suggestion makes sense to me. I went with the second approach.

hokein accepted this revision.Aug 17 2020, 12:46 AM

Thanks!

clang/include/clang/AST/RecursiveASTVisitor.h
1781

nit: just

if (Expr *IDC = ...) {
  ...
} else {
    TRY_TO(TraverseConceptReference(*TC));
}
clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp
3

nit: should be merged in the above line.

This revision is now accepted and ready to land.Aug 17 2020, 12:46 AM
This revision was automatically updated to reflect the committed changes.
nridge marked an inline comment as done.
nridge marked 2 inline comments as done.Aug 17 2020, 9:33 PM