[clang] [Clang][C++26] Implement "Ordering of constraints involving fold expressions (PR #98160)

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 10 06:15:09 PDT 2024


================
@@ -143,13 +157,125 @@ struct NormalizedConstraint {
     return Constraint.get<AtomicConstraint *>();
   }
 
+  FoldExpandedConstraint *getFoldExpandedConstraint() const {
+    assert(isFoldExpanded() &&
+           "getFoldExpandedConstraint called on non-fold-expanded constraint.");
+    return Constraint.get<FoldExpandedConstraint *>();
+  }
+
 private:
   static std::optional<NormalizedConstraint>
   fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E);
   static std::optional<NormalizedConstraint>
   fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E);
 };
 
+struct FoldExpandedConstraint {
+  enum class FoldOperatorKind { And, Or } Kind;
+  NormalizedConstraint Constraint;
+  const Expr *Pattern;
+
+  FoldExpandedConstraint(FoldOperatorKind K, NormalizedConstraint C,
+                         const Expr *Pattern)
+      : Kind(K), Constraint(std::move(C)), Pattern(Pattern) {};
+
+  template <typename AtomicSubsumptionEvaluator>
+  bool subsumes(const FoldExpandedConstraint &Other,
+                const AtomicSubsumptionEvaluator &E) const;
+
+  static bool AreCompatibleForSubsumption(const FoldExpandedConstraint &A,
+                                          const FoldExpandedConstraint &B);
+};
+
+const NormalizedConstraint *getNormalizedAssociatedConstraints(
+    Sema &S, NamedDecl *ConstrainedDecl,
+    ArrayRef<const Expr *> AssociatedConstraints);
+
+template <typename AtomicSubsumptionEvaluator>
+bool subsumes(const NormalForm &PDNF, const NormalForm &QCNF,
+              const AtomicSubsumptionEvaluator &E) {
+  // C++ [temp.constr.order] p2
+  //   Then, P subsumes Q if and only if, for every disjunctive clause Pi in the
+  //   disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in
+  //   the conjuctive normal form of Q, where [...]
+  for (const auto &Pi : PDNF) {
+    for (const auto &Qj : QCNF) {
+      // C++ [temp.constr.order] p2
+      //   - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if
+      //     and only if there exists an atomic constraint Pia in Pi for which
+      //     there exists an atomic constraint, Qjb, in Qj such that Pia
+      //     subsumes Qjb.
+      bool Found = false;
+      for (NormalFormConstraint Pia : Pi) {
+        for (NormalFormConstraint Qjb : Qj) {
+          if (Pia.is<FoldExpandedConstraint *>() &&
+              Qjb.is<FoldExpandedConstraint *>()) {
+            if (Pia.get<FoldExpandedConstraint *>()->subsumes(
+                    *Qjb.get<FoldExpandedConstraint *>(), E)) {
+              Found = true;
+              break;
+            }
+          } else if (Pia.is<AtomicConstraint *>() &&
+                     Qjb.is<AtomicConstraint *>()) {
+            if (E(*Pia.get<AtomicConstraint *>(),
+                  *Qjb.get<AtomicConstraint *>())) {
+              Found = true;
+              break;
+            }
+          }
+        }
+        if (Found)
+          break;
+      }
+      if (!Found)
+        return false;
+    }
+  }
+  return true;
+}
+
+template <typename AtomicSubsumptionEvaluator>
+bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, NamedDecl *DQ,
+              ArrayRef<const Expr *> Q, bool &Subsumes,
+              const AtomicSubsumptionEvaluator &E) {
+  // C++ [temp.constr.order] p2
+  //   In order to determine if a constraint P subsumes a constraint Q, P is
+  //   transformed into disjunctive normal form, and Q is transformed into
+  //   conjunctive normal form. [...]
+  const NormalizedConstraint *PNormalized =
+      getNormalizedAssociatedConstraints(S, DP, P);
+  if (!PNormalized)
+    return true;
+  NormalForm PDNF = makeDNF(*PNormalized);
+
+  const NormalizedConstraint *QNormalized =
+      getNormalizedAssociatedConstraints(S, DQ, Q);
+  if (!QNormalized)
+    return true;
+  NormalForm QCNF = makeCNF(*QNormalized);
+
+  Subsumes = subsumes(PDNF, QCNF, E);
+  return false;
+}
+
+template <typename AtomicSubsumptionEvaluator>
+bool FoldExpandedConstraint::subsumes(
+    const FoldExpandedConstraint &Other,
+    const AtomicSubsumptionEvaluator &E) const {
+
+  // [C++26] [temp.constr.order]
+  // a fold expanded constraint A subsumes another fold expanded constraint B if
+  // they are compatible for subsumption, have the same fold-operator, and the
+  // constraint of A subsumes that of B
+
+  if (Kind != Other.Kind || !AreCompatibleForSubsumption(*this, Other))
+    return false;
+
+  const NormalForm PDNF = makeDNF(this->Constraint);
+  const NormalForm QCNF = makeCNF(Other.Constraint);
----------------
AaronBallman wrote:

Top-level `const`

https://github.com/llvm/llvm-project/pull/98160


More information about the cfe-commits mailing list