llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

<details>
<summary>Changes</summary>

This facilitates debugging with concepts, particularly when we need to check 
complex parameter mappings.

Taking an example from cxx2c-fold-exprs.cpp:

```cpp

template &lt;class T&gt; concept A = (T(), true);
template &lt;class T&gt; concept C = A&lt;T&gt; &amp;&amp; true; // #C

struct S {
  using type = int;
};

template &lt;typename T, typename... U&gt;
consteval int And3() requires (C&lt;typename T::type&gt; &amp;&amp; ... 
&amp;&amp; C&lt;typename U::type&gt;) { // #and3
    return 3;
}
static_assert(And3&lt;S, S&gt;() == 3);

```

It gives us:

```cpp
CompoundConstraint 0x556cfdb54718 &lt;cxx2c-fold-exprs.cpp:9:32, col:80&gt; 
Conjunction
|-ConceptIdConstraint 0x556cfdb54520 &lt;col:32, col:50&gt; C&lt;typename 
T::type&gt;
| `-CompoundConstraint 0x556cfdb544d8 &lt;line:2:32, col:40&gt; Conjunction
|   |-ConceptIdConstraint 0x556cfdb54448 &lt;col:32, col:35&gt; A&lt;T&gt;
|   | |-ParameterMapping Indexes={0} IndexesForSubsumption={}
|   | | `-#<!-- -->0: &lt;class T&gt; -&gt; typename T::type
|   | |   `-TemplateArgument type 0x556cfdb547f8
|   | `-AtomicConstraint 0x556cfdb54400 &lt;line:1:33, col:38&gt; T() , true
|   |   `-ParameterMapping Indexes={0} IndexesForSubsumption={0}
|   |     `-#<!-- -->0: &lt;class T&gt; -&gt; typename T::type
|   |       `-TemplateArgument type 0x556cfdb548d8
|   `-AtomicConstraint 0x556cfdb54490 &lt;line:2:40&gt; true
`-FoldExpandedConstraint 0x556cfdb546d0 &lt;line:9:62, col:80&gt; And 
C&lt;typename U::type&gt;
  `-ConceptIdConstraint 0x556cfdb54688 &lt;col:62, col:80&gt; C&lt;typename 
U::type&gt;
    `-CompoundConstraint 0x556cfdb54640 &lt;line:2:32, col:40&gt; Conjunction
      |-ConceptIdConstraint 0x556cfdb545b0 &lt;col:32, col:35&gt; A&lt;T&gt;
      | |-ParameterMapping Indexes={0} IndexesForSubsumption={}
      | | `-#<!-- -->0: &lt;class T&gt; -&gt; typename U::type
      | |   `-TemplateArgument type 0x556cfdb54ab8
      | `-AtomicConstraint 0x556cfdb54568 &lt;line:1:33, col:38&gt; T() , true
      |   `-ParameterMapping Indexes={0} IndexesForSubsumption={0}
      |     `-#<!-- -->0: &lt;class T&gt; -&gt; typename U::type
      |       `-TemplateArgument type 0x556cfdb54b98
      `-AtomicConstraint 0x556cfdb545f8 &lt;line:2:40&gt; true
```

Since this is mainly for debugging purpose, we don't promise any text stability 
and hence no tests provided.

---
Full diff: https://github.com/llvm/llvm-project/pull/210498.diff


4 Files Affected:

- (modified) clang/include/clang/AST/TemplateBase.h (+2) 
- (modified) clang/include/clang/Sema/SemaConcept.h (+3) 
- (modified) clang/lib/AST/TemplateBase.cpp (+26) 
- (modified) clang/lib/Sema/SemaConcept.cpp (+150) 


``````````diff
diff --git a/clang/include/clang/AST/TemplateBase.h 
b/clang/include/clang/AST/TemplateBase.h
index c0db55ea92cd5..f7d754ea6082b 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -295,6 +295,8 @@ class TemplateArgument {
   /// Return the kind of stored template argument.
   ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; }
 
+  StringRef getKindName() const;
+
   /// Determine whether this template argument has no value.
   bool isNull() const { return getKind() == Null; }
 
diff --git a/clang/include/clang/Sema/SemaConcept.h 
b/clang/include/clang/Sema/SemaConcept.h
index bdd997b18cb08..4bf251d351f06 100644
--- a/clang/include/clang/Sema/SemaConcept.h
+++ b/clang/include/clang/Sema/SemaConcept.h
@@ -276,6 +276,9 @@ struct NormalizedConstraint {
 
   SourceRange getSourceRange() const { return {getBeginLoc(), getEndLoc()}; }
 
+  void dump(ASTContext &Context) const;
+  void dump(llvm::raw_ostream &OS, ASTContext &Context) const;
+
 private:
   friend class Sema;
   static NormalizedConstraint *
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index a5e0dde45364c..d64d3bd5dcc30 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -258,6 +258,32 @@ TemplateArgument::CreatePackCopy(ASTContext &Context,
   return TemplateArgument(Args.copy(Context));
 }
 
+StringRef TemplateArgument::getKindName() const {
+  switch (getKind()) {
+  case TemplateArgument::Null:
+    return "null";
+  case TemplateArgument::Type:
+    return "type";
+  case TemplateArgument::Declaration:
+    return "decl";
+  case TemplateArgument::NullPtr:
+    return "nullptr";
+  case TemplateArgument::Integral:
+    return "integral";
+  case TemplateArgument::Template:
+    return "template";
+  case TemplateArgument::TemplateExpansion:
+    return "template expansion";
+  case TemplateArgument::Expression:
+    return "expression";
+  case TemplateArgument::Pack:
+    return "pack";
+  case TemplateArgument::StructuralValue:
+    return "structural value";
+  }
+  llvm_unreachable("unhandled ArgKind");
+}
+
 TemplateArgumentDependence TemplateArgument::getDependence() const {
   auto Deps = TemplateArgumentDependence::None;
   switch (getKind()) {
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 8831a26224e7d..98d3951c491b0 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TextNodeDumper.h"
 #include "clang/Basic/OperatorPrecedence.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
 #include "clang/Sema/Initialization.h"
@@ -30,6 +31,7 @@
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/TimeProfiler.h"
 
 using namespace clang;
@@ -2965,3 +2967,151 @@ bool SubsumptionChecker::Subsumes(Literal A, Literal B) 
{
   }
   llvm_unreachable("unknown literal kind");
 }
+
+namespace {
+
+class DumpNormalizedConstraint {
+  raw_ostream &OS;
+  const PrintingPolicy &PP;
+  TextNodeDumper TD;
+
+public:
+  DumpNormalizedConstraint(raw_ostream &OS, ASTContext &Context)
+      : OS(OS), PP(Context.getPrintingPolicy()),
+        TD(OS, Context, /*ShowColors=*/false) {}
+
+  void dump(const NormalizedConstraint &N) {
+    TD.AddChild([&] { Traverse(N); });
+  }
+
+private:
+  void Traverse(const NormalizedConstraint &N) {
+    switch (N.getKind()) {
+    case NormalizedConstraint::ConstraintKind::Compound:
+      VisitCompound(static_cast<const CompoundConstraint &>(N));
+      break;
+    case NormalizedConstraint::ConstraintKind::Atomic:
+      VisitAtomic(static_cast<const AtomicConstraint &>(N));
+      break;
+    case NormalizedConstraint::ConstraintKind::ConceptId:
+      VisitConceptId(static_cast<const ConceptIdConstraint &>(N));
+      break;
+    case NormalizedConstraint::ConstraintKind::FoldExpanded:
+      VisitFoldExpanded(static_cast<const FoldExpandedConstraint &>(N));
+      break;
+    }
+  }
+
+  void WriteNodeHeader(const NormalizedConstraint &N, StringRef Kind) {
+    OS << Kind;
+    TD.dumpPointer(&N);
+    TD.dumpSourceRange(N.getSourceRange());
+  }
+
+  void WritePackIndex(const NormalizedConstraintWithParamMapping &N) {
+    if (auto Idx = N.getPackSubstitutionIndex())
+      OS << " SubstIndex=" << *Idx;
+  }
+
+  void VisitCompound(const CompoundConstraint &C) {
+    WriteNodeHeader(C, "CompoundConstraint");
+    OS << " "
+       << (C.getCompoundKind() == NormalizedConstraint::CCK_Conjunction
+               ? "Conjunction"
+               : "Disjunction");
+    TD.AddChild([&] { Traverse(C.getLHS()); });
+    TD.AddChild([&] { Traverse(C.getRHS()); });
+  }
+
+  void VisitAtomic(const AtomicConstraint &A) {
+    WriteNodeHeader(A, "AtomicConstraint");
+    WritePackIndex(A);
+    OS << " ";
+    A.getConstraintExpr()->printPretty(OS, /*Helper=*/nullptr, PP);
+    WriteParameterMapping(A);
+  }
+
+  void VisitConceptId(const ConceptIdConstraint &C) {
+    WriteNodeHeader(C, "ConceptIdConstraint");
+    WritePackIndex(C);
+    OS << " ";
+    if (auto *CSE = C.getConceptSpecializationExpr()) {
+      CSE->printPretty(OS, /*Helper=*/nullptr, PP);
+    } else {
+      C.getConceptId()->print(OS, PP);
+    }
+    WriteParameterMapping(C);
+    TD.AddChild([&] { Traverse(C.getNormalizedConstraint()); });
+  }
+
+  void VisitFoldExpanded(const FoldExpandedConstraint &F) {
+    WriteNodeHeader(F, "FoldExpandedConstraint");
+    OS << " "
+       << (F.getFoldOperator() == FoldExpandedConstraint::FoldOperatorKind::And
+               ? "And"
+               : "Or");
+    WritePackIndex(F);
+    OS << " ";
+    F.getPattern()->printPretty(OS, /*Helper=*/nullptr, PP);
+    WriteParameterMapping(F);
+    TD.AddChild([&] { Traverse(F.getNormalizedPattern()); });
+  }
+
+  void WriteParameterMapping(const NormalizedConstraintWithParamMapping &N) {
+    if (!N.hasParameterMapping() || N.mappingOccurenceList().none())
+      return;
+    TD.AddChild([this, Indexes(N.mappingOccurenceList()),
+                 IndexesForSub(N.mappingOccurenceListForSubsumption()),
+                 Mapping(N.getParameterMapping()),
+                 TPL(N.getUsedTemplateParamList())] {
+      OS << "ParameterMapping";
+      WriteOccurenceList("Indexes", Indexes);
+      WriteOccurenceList("IndexesForSubsumption", IndexesForSub);
+      unsigned Slot = 0;
+      for (unsigned ParamIndex : Indexes.set_bits()) {
+        TD.AddChild([this, Slot, ParamIndex, Mapping, TPL] {
+          OS << "#" << ParamIndex << ": ";
+          if (TPL && Slot < TPL->size()) {
+            const NamedDecl *Param = TPL->getParam(Slot);
+            OS << "<";
+            Param->print(OS, PP);
+            OS << ">";
+          }
+          OS << " -> ";
+          Mapping[Slot].getArgument().print(PP, OS,
+                                            /*IncludeType=*/false);
+          TD.AddChild([this, Slot, Mapping] {
+            const TemplateArgument &TA = Mapping[Slot].getArgument();
+            OS << "TemplateArgument " << TA.getKindName();
+            TD.dumpPointer(&TA);
+          });
+        });
+        ++Slot;
+      }
+    });
+  }
+
+  void WriteOccurenceList(StringRef Label,
+                          const NormalizedConstraint::OccurenceList &BV) {
+    if (BV.none())
+      return;
+    OS << " " << Label << "={"
+       << llvm::join(
+              llvm::map_range(
+                  llvm::make_range(BV.set_bits_begin(), BV.set_bits_end()),
+                  [](unsigned I) { return llvm::to_string(I); }),
+              ", ")
+       << '}';
+  }
+};
+
+} // namespace
+
+LLVM_DUMP_METHOD void NormalizedConstraint::dump(ASTContext &Context) const {
+  dump(llvm::errs(), Context);
+}
+
+LLVM_DUMP_METHOD void NormalizedConstraint::dump(llvm::raw_ostream &OS,
+                                                 ASTContext &Context) const {
+  return DumpNormalizedConstraint(OS, Context).dump(*this);
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/210498
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to