[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