diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/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 concept Fooable = requires (T t) { t.foo(); };"}); + + // constrained-parameter + Code = R"cpp( + template + 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 concept Fooable = true;"}); + + // partial-concept-id + Code = R"cpp( + template + 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 concept Fooable = true;"}); } TEST_F(TargetDeclTest, FunctionTemplate) { diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h --- a/clang/include/clang/AST/ExprConcepts.h +++ b/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 diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1839,8 +1839,10 @@ // D is the "T" in something like "template 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())); })