Add dumping support for RequiresExpr.
In passing, fix an ast-print bug that inserted a spurious extra `;` after a concept definition.
This commit is contained in:
parent
d86b0073cf
commit
ef227b32b6
|
@ -53,6 +53,7 @@ struct {
|
|||
void Visit(const OMPClause *C);
|
||||
void Visit(const BlockDecl::Capture &C);
|
||||
void Visit(const GenericSelectionExpr::ConstAssociation &A);
|
||||
void Visit(const concepts::Requirement *R);
|
||||
void Visit(const APValue &Value, QualType Ty);
|
||||
};
|
||||
*/
|
||||
|
@ -141,7 +142,8 @@ public:
|
|||
ConstStmtVisitor<Derived>::Visit(S);
|
||||
|
||||
// Some statements have custom mechanisms for dumping their children.
|
||||
if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S))
|
||||
if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) ||
|
||||
isa<RequiresExpr>(S))
|
||||
return;
|
||||
|
||||
if (Traversal == TK_IgnoreUnlessSpelledInSource &&
|
||||
|
@ -228,6 +230,28 @@ public:
|
|||
});
|
||||
}
|
||||
|
||||
void Visit(const concepts::Requirement *R) {
|
||||
getNodeDelegate().AddChild([=] {
|
||||
getNodeDelegate().Visit(R);
|
||||
if (!R)
|
||||
return;
|
||||
if (auto *TR = dyn_cast<concepts::TypeRequirement>(R)) {
|
||||
if (!TR->isSubstitutionFailure())
|
||||
Visit(TR->getType()->getType().getTypePtr());
|
||||
} else if (auto *ER = dyn_cast<concepts::ExprRequirement>(R)) {
|
||||
if (!ER->isExprSubstitutionFailure())
|
||||
Visit(ER->getExpr());
|
||||
if (!ER->getReturnTypeRequirement().isEmpty())
|
||||
Visit(ER->getReturnTypeRequirement()
|
||||
.getTypeConstraint()
|
||||
->getImmediatelyDeclaredConstraint());
|
||||
} else if (auto *NR = dyn_cast<concepts::NestedRequirement>(R)) {
|
||||
if (!NR->isSubstitutionFailure())
|
||||
Visit(NR->getConstraintExpr());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Visit(const APValue &Value, QualType Ty) {
|
||||
getNodeDelegate().AddChild([=] { getNodeDelegate().Visit(Value, Ty); });
|
||||
}
|
||||
|
@ -689,6 +713,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void VisitRequiresExpr(const RequiresExpr *E) {
|
||||
for (auto *D : E->getLocalParameters())
|
||||
Visit(D);
|
||||
for (auto *R : E->getRequirements())
|
||||
Visit(R);
|
||||
}
|
||||
|
||||
void VisitLambdaExpr(const LambdaExpr *Node) {
|
||||
if (Traversal == TK_IgnoreUnlessSpelledInSource) {
|
||||
for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "clang/AST/AttrVisitor.h"
|
||||
#include "clang/AST/CommentCommandTraits.h"
|
||||
#include "clang/AST/CommentVisitor.h"
|
||||
#include "clang/AST/ExprConcepts.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Mangle.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
@ -204,6 +205,7 @@ public:
|
|||
void Visit(const OMPClause *C);
|
||||
void Visit(const BlockDecl::Capture &C);
|
||||
void Visit(const GenericSelectionExpr::ConstAssociation &A);
|
||||
void Visit(const concepts::Requirement *R);
|
||||
void Visit(const APValue &Value, QualType Ty);
|
||||
|
||||
void VisitTypedefType(const TypedefType *TT);
|
||||
|
@ -290,6 +292,7 @@ public:
|
|||
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE);
|
||||
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
|
||||
void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME);
|
||||
void VisitRequiresExpr(const RequiresExpr *RE);
|
||||
|
||||
void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE);
|
||||
void VisitObjCMessageExpr(const ObjCMessageExpr *OME);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "clang/AST/CommentCommandTraits.h"
|
||||
#include "clang/AST/CommentVisitor.h"
|
||||
#include "clang/AST/DeclVisitor.h"
|
||||
#include "clang/AST/ExprConcepts.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/TemplateArgumentVisitor.h"
|
||||
|
@ -188,6 +189,8 @@ public:
|
|||
|
||||
void Visit(const GenericSelectionExpr::ConstAssociation &A);
|
||||
|
||||
void Visit(const concepts::Requirement *R);
|
||||
|
||||
void Visit(const APValue &Value, QualType Ty);
|
||||
|
||||
void dumpPointer(const void *Ptr);
|
||||
|
@ -296,6 +299,7 @@ public:
|
|||
void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node);
|
||||
void VisitOMPIteratorExpr(const OMPIteratorExpr *Node);
|
||||
void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *Node);
|
||||
void VisitRequiresExpr(const RequiresExpr *Node);
|
||||
|
||||
void VisitRValueReferenceType(const ReferenceType *T);
|
||||
void VisitArrayType(const ArrayType *T);
|
||||
|
|
|
@ -1146,7 +1146,6 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
|
|||
Out << "concept " << Concept->getName() << " = " ;
|
||||
Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy, Indentation,
|
||||
"\n", &Context);
|
||||
Out << ";";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,6 +185,35 @@ void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
|
|||
attributeOnlyIfTrue("selected", A.isSelected());
|
||||
}
|
||||
|
||||
void JSONNodeDumper::Visit(const concepts::Requirement *R) {
|
||||
if (!R)
|
||||
return;
|
||||
|
||||
switch (R->getKind()) {
|
||||
case concepts::Requirement::RK_Type:
|
||||
JOS.attribute("kind", "TypeRequirement");
|
||||
break;
|
||||
case concepts::Requirement::RK_Simple:
|
||||
JOS.attribute("kind", "SimpleRequirement");
|
||||
break;
|
||||
case concepts::Requirement::RK_Compound:
|
||||
JOS.attribute("kind", "CompoundRequirement");
|
||||
break;
|
||||
case concepts::Requirement::RK_Nested:
|
||||
JOS.attribute("kind", "NestedRequirement");
|
||||
break;
|
||||
}
|
||||
|
||||
if (auto *ER = dyn_cast<concepts::ExprRequirement>(R))
|
||||
attributeOnlyIfTrue("noexcept", ER->hasNoexceptRequirement());
|
||||
|
||||
attributeOnlyIfTrue("isDependent", R->isDependent());
|
||||
if (!R->isDependent())
|
||||
JOS.attribute("satisfied", R->isSatisfied());
|
||||
attributeOnlyIfTrue("containsUnexpandedPack",
|
||||
R->containsUnexpandedParameterPack());
|
||||
}
|
||||
|
||||
void JSONNodeDumper::Visit(const APValue &Value, QualType Ty) {
|
||||
std::string Str;
|
||||
llvm::raw_string_ostream OS(Str);
|
||||
|
@ -713,9 +742,13 @@ void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) {
|
|||
void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) {
|
||||
if (ND && ND->getDeclName()) {
|
||||
JOS.attribute("name", ND->getNameAsString());
|
||||
std::string MangledName = ASTNameGen.getName(ND);
|
||||
if (!MangledName.empty())
|
||||
JOS.attribute("mangledName", MangledName);
|
||||
// FIXME: There are likely other contexts in which it makes no sense to ask
|
||||
// for a mangled name.
|
||||
if (!isa<RequiresExprBodyDecl>(ND->getDeclContext())) {
|
||||
std::string MangledName = ASTNameGen.getName(ND);
|
||||
if (!MangledName.empty())
|
||||
JOS.attribute("mangledName", MangledName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1415,6 +1448,11 @@ void JSONNodeDumper::VisitCXXDependentScopeMemberExpr(
|
|||
}
|
||||
}
|
||||
|
||||
void JSONNodeDumper::VisitRequiresExpr(const RequiresExpr *RE) {
|
||||
if (!RE->isValueDependent())
|
||||
JOS.attribute("satisfied", RE->isSatisfied());
|
||||
}
|
||||
|
||||
void JSONNodeDumper::VisitIntegerLiteral(const IntegerLiteral *IL) {
|
||||
llvm::SmallString<16> Buffer;
|
||||
IL->getValue().toString(Buffer,
|
||||
|
|
|
@ -356,6 +356,46 @@ void TextNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
|
|||
OS << " selected";
|
||||
}
|
||||
|
||||
void TextNodeDumper::Visit(const concepts::Requirement *R) {
|
||||
if (!R) {
|
||||
ColorScope Color(OS, ShowColors, NullColor);
|
||||
OS << "<<<NULL>>> Requirement";
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ColorScope Color(OS, ShowColors, StmtColor);
|
||||
switch (R->getKind()) {
|
||||
case concepts::Requirement::RK_Type:
|
||||
OS << "TypeRequirement";
|
||||
break;
|
||||
case concepts::Requirement::RK_Simple:
|
||||
OS << "SimpleRequirement";
|
||||
break;
|
||||
case concepts::Requirement::RK_Compound:
|
||||
OS << "CompoundRequirement";
|
||||
break;
|
||||
case concepts::Requirement::RK_Nested:
|
||||
OS << "NestedRequirement";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dumpPointer(R);
|
||||
|
||||
if (auto *ER = dyn_cast<concepts::ExprRequirement>(R)) {
|
||||
if (ER->hasNoexceptRequirement())
|
||||
OS << " noexcept";
|
||||
}
|
||||
|
||||
if (R->isDependent())
|
||||
OS << " dependent";
|
||||
else
|
||||
OS << (R->isSatisfied() ? " satisfied" : " unsatisfied");
|
||||
if (R->containsUnexpandedParameterPack())
|
||||
OS << " contains_unexpanded_pack";
|
||||
}
|
||||
|
||||
static double GetApproxValue(const llvm::APFloat &F) {
|
||||
llvm::APFloat V = F;
|
||||
bool ignored;
|
||||
|
@ -1366,6 +1406,12 @@ void TextNodeDumper::VisitConceptSpecializationExpr(
|
|||
dumpBareDeclRef(Node->getFoundDecl());
|
||||
}
|
||||
|
||||
void TextNodeDumper::VisitRequiresExpr(
|
||||
const RequiresExpr *Node) {
|
||||
if (!Node->isValueDependent())
|
||||
OS << (Node->isSatisfied() ? " satisfied" : " unsatisfied");
|
||||
}
|
||||
|
||||
void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) {
|
||||
if (T->isSpelledAsLValue())
|
||||
OS << " written as lvalue reference";
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -fsyntax-only %s
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-print %s -o %t.1.cpp
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-print %t.1.cpp -o %t.2.cpp
|
||||
// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s
|
||||
// RUN: %clang_cc1 -std=c++20 -ast-print %s -o %t.1.cpp
|
||||
// RUN: %clang_cc1 -std=c++20 -ast-print %t.1.cpp -o %t.2.cpp
|
||||
// RUN: diff %t.1.cpp %t.2.cpp
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-dump %s
|
||||
// RUN: %clang_cc1 -std=c++14 -ast-dump-all %s
|
||||
// RUN: %clang_cc1 -std=c++14 -fdump-record-layouts %s
|
||||
// RUN: %clang_cc1 -std=c++20 -ast-dump %s
|
||||
// RUN: %clang_cc1 -std=c++20 -ast-dump-all %s
|
||||
// RUN: %clang_cc1 -std=c++20 -ast-dump=json %s
|
||||
// RUN: %clang_cc1 -std=c++20 -fdump-record-layouts %s
|
||||
|
||||
#include "cxx-language-features.inc"
|
||||
|
|
|
@ -65,3 +65,15 @@ private:
|
|||
template <typename T> T varTemplate = 0;
|
||||
|
||||
static_assert(true, "");
|
||||
|
||||
// Concepts
|
||||
template<typename T> concept True = true;
|
||||
template<typename T> concept Concept = requires (T a) {
|
||||
a;
|
||||
{ a() } noexcept -> True;
|
||||
requires false || true;
|
||||
typename T::type;
|
||||
};
|
||||
template<typename T> void constrained1() requires Concept<T>;
|
||||
template<Concept T> void constrained2();
|
||||
void constrained3(Concept auto x);
|
||||
|
|
Loading…
Reference in New Issue