Skip to content

Commit 00d7b7d

Browse files
[clang] Fix visitation of ConceptSpecializationExpr in constrained-parameter
Summary: RecursiveASTVisitor needs to traverse TypeConstraint::ImmediatelyDeclaredConstraint Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D84136
1 parent 15673d7 commit 00d7b7d

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,28 @@ TEST_F(TargetDeclTest, Concept) {
442442
)cpp";
443443
EXPECT_DECLS("ConceptSpecializationExpr",
444444
{"template <typename T> concept Fooable = true;"});
445+
446+
// constrained-parameter
447+
Code = R"cpp(
448+
template <typename T>
449+
concept Fooable = true;
450+
451+
template <[[Fooable]] T>
452+
void bar(T t);
453+
)cpp";
454+
EXPECT_DECLS("ConceptSpecializationExpr",
455+
{"template <typename T> concept Fooable = true;"});
456+
457+
// partial-concept-id
458+
Code = R"cpp(
459+
template <typename T, typename U>
460+
concept Fooable = true;
461+
462+
template <[[Fooable]]<int> T>
463+
void bar(T t);
464+
)cpp";
465+
EXPECT_DECLS("ConceptSpecializationExpr",
466+
{"template <typename T, typename U> concept Fooable = true;"});
445467
}
446468

447469
TEST_F(TargetDeclTest, FunctionTemplate) {

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,8 +1777,17 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
17771777
// D is the "T" in something like "template<typename T> class vector;"
17781778
if (D->getTypeForDecl())
17791779
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
1780-
if (const auto *TC = D->getTypeConstraint())
1781-
TRY_TO(TraverseConceptReference(*TC));
1780+
if (const auto *TC = D->getTypeConstraint()) {
1781+
if (Expr *IDC = TC->getImmediatelyDeclaredConstraint()) {
1782+
TRY_TO(TraverseStmt(IDC));
1783+
} else {
1784+
// Avoid traversing the ConceptReference in the TypeCosntraint
1785+
// if we have an immediately-declared-constraint, otherwise
1786+
// we'll end up visiting the concept and the arguments in
1787+
// the TC twice.
1788+
TRY_TO(TraverseConceptReference(*TC));
1789+
}
1790+
}
17821791
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
17831792
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
17841793
})

clang/unittests/Tooling/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_clang_unittest(ToolingTests
2222
RecursiveASTVisitorTests/Attr.cpp
2323
RecursiveASTVisitorTests/Callbacks.cpp
2424
RecursiveASTVisitorTests/Class.cpp
25+
RecursiveASTVisitorTests/Concept.cpp
2526
RecursiveASTVisitorTests/ConstructExpr.cpp
2627
RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp
2728
RecursiveASTVisitorTests/CXXMemberCall.cpp
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===- unittest/Tooling/RecursiveASTVisitorTests/Concept.cpp----------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "TestVisitor.h"
10+
#include "clang/AST/ExprConcepts.h"
11+
12+
using namespace clang;
13+
14+
namespace {
15+
16+
struct ConceptVisitor : ExpectedLocationVisitor<ConceptVisitor> {
17+
bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
18+
++ConceptSpecializationExprsVisited;
19+
return true;
20+
}
21+
bool TraverseConceptReference(const ConceptReference &R) {
22+
++ConceptReferencesTraversed;
23+
return true;
24+
}
25+
26+
int ConceptSpecializationExprsVisited = 0;
27+
int ConceptReferencesTraversed = 0;
28+
};
29+
30+
TEST(RecursiveASTVisitor, ConstrainedParameter) {
31+
ConceptVisitor Visitor;
32+
EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
33+
"template <Fooable T> void bar(T);",
34+
ConceptVisitor::Lang_CXX2a));
35+
// Check that we visit the "Fooable T" template parameter's TypeConstraint's
36+
// ImmediatelyDeclaredConstraint, which is a ConceptSpecializationExpr.
37+
EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited);
38+
// There are two ConceptReference objects in the AST: the base subobject
39+
// of the ConceptSpecializationExpr, and the base subobject of the
40+
// TypeConstraint itself. To avoid traversing the concept and arguments
41+
// multiple times, we only traverse one.
42+
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
43+
}
44+
45+
} // end anonymous namespace

0 commit comments

Comments
 (0)