[clang] ef227b3 - Add dumping support for RequiresExpr.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 30 14:27:30 PDT 2021
Author: Richard Smith
Date: 2021-06-30T14:27:19-07:00
New Revision: ef227b32b63c53ca81ebd410c7fbd5af8fc22ec5
URL: https://github.com/llvm/llvm-project/commit/ef227b32b63c53ca81ebd410c7fbd5af8fc22ec5
DIFF: https://github.com/llvm/llvm-project/commit/ef227b32b63c53ca81ebd410c7fbd5af8fc22ec5.diff
LOG: Add dumping support for RequiresExpr.
In passing, fix an ast-print bug that inserted a spurious extra `;`
after a concept definition.
Added:
Modified:
clang/include/clang/AST/ASTNodeTraverser.h
clang/include/clang/AST/JSONNodeDumper.h
clang/include/clang/AST/TextNodeDumper.h
clang/lib/AST/DeclPrinter.cpp
clang/lib/AST/JSONNodeDumper.cpp
clang/lib/AST/TextNodeDumper.cpp
clang/test/Coverage/ast-printing.cpp
clang/test/Coverage/cxx-language-features.inc
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index c4f0355b352e..18e7f491f222 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -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 @@ class ASTNodeTraverser
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 @@ class ASTNodeTraverser
});
}
+ 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 @@ class ASTNodeTraverser
}
}
+ 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) {
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index 1f3585910a40..a96e21993e20 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -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 @@ class JSONNodeDumper
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 @@ class JSONNodeDumper
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);
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 4dc68d5237b4..0eb0031de11f 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -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 @@ class TextNodeDumper
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 @@ class TextNodeDumper
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);
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 516be54b90f6..4dcf3d0e6ab1 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -1146,7 +1146,6 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
Out << "concept " << Concept->getName() << " = " ;
Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy, Indentation,
"\n", &Context);
- Out << ";";
}
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index e3b1209bf5cc..f09f9d38759f 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -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,
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 38e01fc66408..33f914f9f886 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -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";
diff --git a/clang/test/Coverage/ast-printing.cpp b/clang/test/Coverage/ast-printing.cpp
index 948b67eec6b0..c1ce70478d74 100644
--- a/clang/test/Coverage/ast-printing.cpp
+++ b/clang/test/Coverage/ast-printing.cpp
@@ -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"
diff --git a/clang/test/Coverage/cxx-language-features.inc b/clang/test/Coverage/cxx-language-features.inc
index 1e3b0744950a..4eaba456f884 100644
--- a/clang/test/Coverage/cxx-language-features.inc
+++ b/clang/test/Coverage/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);
More information about the cfe-commits
mailing list