forked from OSchip/llvm-project
[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
This commit is contained in:
parent
15673d748a
commit
00d7b7d014
|
|
@ -442,6 +442,28 @@ TEST_F(TargetDeclTest, Concept) {
|
|||
)cpp";
|
||||
EXPECT_DECLS("ConceptSpecializationExpr",
|
||||
{"template <typename T> concept Fooable = true;"});
|
||||
|
||||
// constrained-parameter
|
||||
Code = R"cpp(
|
||||
template <typename T>
|
||||
concept Fooable = true;
|
||||
|
||||
template <[[Fooable]] T>
|
||||
void bar(T t);
|
||||
)cpp";
|
||||
EXPECT_DECLS("ConceptSpecializationExpr",
|
||||
{"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";
|
||||
EXPECT_DECLS("ConceptSpecializationExpr",
|
||||
{"template <typename T, typename U> concept Fooable = true;"});
|
||||
}
|
||||
|
||||
TEST_F(TargetDeclTest, FunctionTemplate) {
|
||||
|
|
|
|||
|
|
@ -1777,8 +1777,17 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
|
|||
// 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())
|
||||
TRY_TO(TraverseConceptReference(*TC));
|
||||
if (const auto *TC = D->getTypeConstraint()) {
|
||||
if (Expr *IDC = TC->getImmediatelyDeclaredConstraint()) {
|
||||
TRY_TO(TraverseStmt(IDC));
|
||||
} else {
|
||||
// Avoid traversing the ConceptReference in the TypeCosntraint
|
||||
// if we have an immediately-declared-constraint, otherwise
|
||||
// we'll end up visiting the concept and the arguments in
|
||||
// the TC twice.
|
||||
TRY_TO(TraverseConceptReference(*TC));
|
||||
}
|
||||
}
|
||||
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
|
||||
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ add_clang_unittest(ToolingTests
|
|||
RecursiveASTVisitorTests/Attr.cpp
|
||||
RecursiveASTVisitorTests/Callbacks.cpp
|
||||
RecursiveASTVisitorTests/Class.cpp
|
||||
RecursiveASTVisitorTests/Concept.cpp
|
||||
RecursiveASTVisitorTests/ConstructExpr.cpp
|
||||
RecursiveASTVisitorTests/CXXBoolLiteralExpr.cpp
|
||||
RecursiveASTVisitorTests/CXXMemberCall.cpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
//===- unittest/Tooling/RecursiveASTVisitorTests/Concept.cpp----------------==//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TestVisitor.h"
|
||||
#include "clang/AST/ExprConcepts.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
|
||||
struct ConceptVisitor : ExpectedLocationVisitor<ConceptVisitor> {
|
||||
bool VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
|
||||
++ConceptSpecializationExprsVisited;
|
||||
return true;
|
||||
}
|
||||
bool TraverseConceptReference(const ConceptReference &R) {
|
||||
++ConceptReferencesTraversed;
|
||||
return true;
|
||||
}
|
||||
|
||||
int ConceptSpecializationExprsVisited = 0;
|
||||
int ConceptReferencesTraversed = 0;
|
||||
};
|
||||
|
||||
TEST(RecursiveASTVisitor, ConstrainedParameter) {
|
||||
ConceptVisitor Visitor;
|
||||
EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
|
||||
"template <Fooable T> void bar(T);",
|
||||
ConceptVisitor::Lang_CXX2a));
|
||||
// Check that we visit the "Fooable T" template parameter's TypeConstraint's
|
||||
// ImmediatelyDeclaredConstraint, which is a ConceptSpecializationExpr.
|
||||
EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited);
|
||||
// There are two ConceptReference objects in the AST: the base subobject
|
||||
// of the ConceptSpecializationExpr, and the base subobject of the
|
||||
// TypeConstraint itself. To avoid traversing the concept and arguments
|
||||
// multiple times, we only traverse one.
|
||||
EXPECT_EQ(1, Visitor.ConceptReferencesTraversed);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
Loading…
Reference in New Issue