nridge created this revision. Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman, jkorous, MaskRay, ilya-biryukov. Herald added a project: clang.
There were two problems here: - RecursiveASTVisitor did not traverse TypeConstraint::ImmediatelyDeclaredConstraint - ConceptSpecializationExpr::getEndLoc() returned an invalid location in case of a constrained-parameter with no explicit arguments Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D84136 Files: clang-tools-extra/clangd/unittests/FindTargetTests.cpp clang/include/clang/AST/ExprConcepts.h clang/include/clang/AST/RecursiveASTVisitor.h Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1839,8 +1839,10 @@ // D is the "T" in something like "template<typename T> class vector;" if (D->getTypeForDecl()) TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); - if (const auto *TC = D->getTypeConstraint()) + if (const auto *TC = D->getTypeConstraint()) { + TRY_TO(TraverseStmt(TC->getImmediatelyDeclaredConstraint())); TRY_TO(TraverseConceptReference(*TC)); + } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); }) Index: clang/include/clang/AST/ExprConcepts.h =================================================================== --- clang/include/clang/AST/ExprConcepts.h +++ clang/include/clang/AST/ExprConcepts.h @@ -126,7 +126,11 @@ } SourceLocation getEndLoc() const LLVM_READONLY { - return ArgsAsWritten->RAngleLoc; + // If the ConceptSpecializationExpr is the ImmediatelyDeclaredConstraint + // of a TypeConstraint written syntactically as a constrained-parameter, + // there may not be a template argument list. + return ArgsAsWritten->RAngleLoc.isValid() ? ArgsAsWritten->RAngleLoc + : ConceptName.getEndLoc(); } // Iterators Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -407,6 +407,34 @@ // FIXME: Should we truncate the pretty-printed form of a concept decl // somewhere? {"template <typename T> concept Fooable = requires (T t) { t.foo(); };"}); + + // constrained-parameter + Code = R"cpp( + template <typename T> + concept Fooable = true; + + template <[[Fooable]] T> + void bar(T t); + )cpp"; + Flags.push_back("-std=c++20"); + EXPECT_DECLS("ConceptSpecializationExpr", + // FIXME: Should we truncate the pretty-printed form of a concept + // decl somewhere? + {"template <typename T> concept Fooable = true;"}); + + // partial-concept-id + Code = R"cpp( + template <typename T, typename U> + concept Fooable = true; + + template <[[Fooable]]<int> T> + void bar(T t); + )cpp"; + Flags.push_back("-std=c++20"); + EXPECT_DECLS("ConceptSpecializationExpr", + // FIXME: Should we truncate the pretty-printed form of a concept + // decl somewhere? + {"template <typename T, typename U> concept Fooable = true;"}); } TEST_F(TargetDeclTest, FunctionTemplate) {
Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -1839,8 +1839,10 @@ // D is the "T" in something like "template<typename T> class vector;" if (D->getTypeForDecl()) TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); - if (const auto *TC = D->getTypeConstraint()) + if (const auto *TC = D->getTypeConstraint()) { + TRY_TO(TraverseStmt(TC->getImmediatelyDeclaredConstraint())); TRY_TO(TraverseConceptReference(*TC)); + } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); }) Index: clang/include/clang/AST/ExprConcepts.h =================================================================== --- clang/include/clang/AST/ExprConcepts.h +++ clang/include/clang/AST/ExprConcepts.h @@ -126,7 +126,11 @@ } SourceLocation getEndLoc() const LLVM_READONLY { - return ArgsAsWritten->RAngleLoc; + // If the ConceptSpecializationExpr is the ImmediatelyDeclaredConstraint + // of a TypeConstraint written syntactically as a constrained-parameter, + // there may not be a template argument list. + return ArgsAsWritten->RAngleLoc.isValid() ? ArgsAsWritten->RAngleLoc + : ConceptName.getEndLoc(); } // Iterators Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -407,6 +407,34 @@ // FIXME: Should we truncate the pretty-printed form of a concept decl // somewhere? {"template <typename T> concept Fooable = requires (T t) { t.foo(); };"}); + + // constrained-parameter + Code = R"cpp( + template <typename T> + concept Fooable = true; + + template <[[Fooable]] T> + void bar(T t); + )cpp"; + Flags.push_back("-std=c++20"); + EXPECT_DECLS("ConceptSpecializationExpr", + // FIXME: Should we truncate the pretty-printed form of a concept + // decl somewhere? + {"template <typename T> concept Fooable = true;"}); + + // partial-concept-id + Code = R"cpp( + template <typename T, typename U> + concept Fooable = true; + + template <[[Fooable]]<int> T> + void bar(T t); + )cpp"; + Flags.push_back("-std=c++20"); + EXPECT_DECLS("ConceptSpecializationExpr", + // FIXME: Should we truncate the pretty-printed form of a concept + // decl somewhere? + {"template <typename T, typename U> concept Fooable = true;"}); } TEST_F(TargetDeclTest, FunctionTemplate) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits