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 <class T> concept A = (T(), true);
template <class T> concept C = A<T> && true; // #C
struct S {
using type = int;
};
template <typename T, typename... U>
consteval int And3() requires (C<typename T::type> && ...
&& C<typename U::type>) { // #and3
return 3;
}
static_assert(And3<S, S>() == 3);
```
It gives us:
```cpp
CompoundConstraint 0x556cfdb54718 <cxx2c-fold-exprs.cpp:9:32, col:80>
Conjunction
|-ConceptIdConstraint 0x556cfdb54520 <col:32, col:50> C<typename
T::type>
| `-CompoundConstraint 0x556cfdb544d8 <line:2:32, col:40> Conjunction
| |-ConceptIdConstraint 0x556cfdb54448 <col:32, col:35> A<T>
| | |-ParameterMapping Indexes={0} IndexesForSubsumption={}
| | | `-#<!-- -->0: <class T> -> typename T::type
| | | `-TemplateArgument type 0x556cfdb547f8
| | `-AtomicConstraint 0x556cfdb54400 <line:1:33, col:38> T() , true
| | `-ParameterMapping Indexes={0} IndexesForSubsumption={0}
| | `-#<!-- -->0: <class T> -> typename T::type
| | `-TemplateArgument type 0x556cfdb548d8
| `-AtomicConstraint 0x556cfdb54490 <line:2:40> true
`-FoldExpandedConstraint 0x556cfdb546d0 <line:9:62, col:80> And
C<typename U::type>
`-ConceptIdConstraint 0x556cfdb54688 <col:62, col:80> C<typename
U::type>
`-CompoundConstraint 0x556cfdb54640 <line:2:32, col:40> Conjunction
|-ConceptIdConstraint 0x556cfdb545b0 <col:32, col:35> A<T>
| |-ParameterMapping Indexes={0} IndexesForSubsumption={}
| | `-#<!-- -->0: <class T> -> typename U::type
| | `-TemplateArgument type 0x556cfdb54ab8
| `-AtomicConstraint 0x556cfdb54568 <line:1:33, col:38> T() , true
| `-ParameterMapping Indexes={0} IndexesForSubsumption={0}
| `-#<!-- -->0: <class T> -> typename U::type
| `-TemplateArgument type 0x556cfdb54b98
`-AtomicConstraint 0x556cfdb545f8 <line:2:40> 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