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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits