File indexing completed on 2026-05-10 08:37:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H
0014 #define LLVM_CLANG_SEMA_SEMACONCEPT_H
0015 #include "clang/AST/ASTConcept.h"
0016 #include "clang/AST/ASTContext.h"
0017 #include "clang/AST/Expr.h"
0018 #include "clang/AST/DeclTemplate.h"
0019 #include "clang/Basic/SourceLocation.h"
0020 #include "llvm/ADT/PointerUnion.h"
0021 #include "llvm/ADT/SmallVector.h"
0022 #include <optional>
0023 #include <string>
0024 #include <utility>
0025
0026 namespace clang {
0027 class Sema;
0028
0029 enum { ConstraintAlignment = 8 };
0030
0031 struct alignas(ConstraintAlignment) AtomicConstraint {
0032 const Expr *ConstraintExpr;
0033 NamedDecl *ConstraintDecl;
0034 std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping;
0035
0036 AtomicConstraint(const Expr *ConstraintExpr, NamedDecl *ConstraintDecl)
0037 : ConstraintExpr(ConstraintExpr), ConstraintDecl(ConstraintDecl) {};
0038
0039 bool hasMatchingParameterMapping(ASTContext &C,
0040 const AtomicConstraint &Other) const {
0041 if (!ParameterMapping != !Other.ParameterMapping)
0042 return false;
0043 if (!ParameterMapping)
0044 return true;
0045 if (ParameterMapping->size() != Other.ParameterMapping->size())
0046 return false;
0047
0048 for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
0049 llvm::FoldingSetNodeID IDA, IDB;
0050 C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
0051 .Profile(IDA, C);
0052 C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
0053 .Profile(IDB, C);
0054 if (IDA != IDB)
0055 return false;
0056 }
0057 return true;
0058 }
0059
0060 bool subsumes(ASTContext &C, const AtomicConstraint &Other) const {
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 if (ConstraintExpr != Other.ConstraintExpr)
0074 return false;
0075
0076
0077 return hasMatchingParameterMapping(C, Other);
0078 }
0079 };
0080
0081 struct alignas(ConstraintAlignment) FoldExpandedConstraint;
0082
0083 using NormalFormConstraint =
0084 llvm::PointerUnion<AtomicConstraint *, FoldExpandedConstraint *>;
0085 struct NormalizedConstraint;
0086 using NormalForm =
0087 llvm::SmallVector<llvm::SmallVector<NormalFormConstraint, 2>, 4>;
0088
0089
0090
0091
0092
0093 NormalForm makeCNF(const NormalizedConstraint &Normalized);
0094
0095
0096
0097
0098
0099 NormalForm makeDNF(const NormalizedConstraint &Normalized);
0100
0101 struct alignas(ConstraintAlignment) NormalizedConstraintPair;
0102
0103
0104
0105
0106 struct NormalizedConstraint {
0107 friend class Sema;
0108
0109 enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
0110
0111 using CompoundConstraint = llvm::PointerIntPair<NormalizedConstraintPair *, 1,
0112 CompoundConstraintKind>;
0113
0114 llvm::PointerUnion<AtomicConstraint *, FoldExpandedConstraint *,
0115 CompoundConstraint>
0116 Constraint;
0117
0118 NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
0119 NormalizedConstraint(FoldExpandedConstraint *C) : Constraint{C} {};
0120
0121 NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
0122 NormalizedConstraint RHS, CompoundConstraintKind Kind);
0123
0124 NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other);
0125 NormalizedConstraint(NormalizedConstraint &&Other):
0126 Constraint(Other.Constraint) {
0127 Other.Constraint = nullptr;
0128 }
0129 NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete;
0130 NormalizedConstraint &operator=(NormalizedConstraint &&Other) {
0131 if (&Other != this) {
0132 NormalizedConstraint Temp(std::move(Other));
0133 std::swap(Constraint, Temp.Constraint);
0134 }
0135 return *this;
0136 }
0137
0138 bool isAtomic() const { return llvm::isa<AtomicConstraint *>(Constraint); }
0139 bool isFoldExpanded() const {
0140 return llvm::isa<FoldExpandedConstraint *>(Constraint);
0141 }
0142 bool isCompound() const { return llvm::isa<CompoundConstraint>(Constraint); }
0143
0144 CompoundConstraintKind getCompoundKind() const;
0145
0146 NormalizedConstraint &getLHS() const;
0147 NormalizedConstraint &getRHS() const;
0148
0149 AtomicConstraint *getAtomicConstraint() const;
0150
0151 FoldExpandedConstraint *getFoldExpandedConstraint() const;
0152
0153 private:
0154 static std::optional<NormalizedConstraint>
0155 fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E);
0156 static std::optional<NormalizedConstraint>
0157 fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E);
0158 };
0159
0160 struct alignas(ConstraintAlignment) NormalizedConstraintPair {
0161 NormalizedConstraint LHS, RHS;
0162 };
0163
0164 struct alignas(ConstraintAlignment) FoldExpandedConstraint {
0165 enum class FoldOperatorKind { And, Or } Kind;
0166 NormalizedConstraint Constraint;
0167 const Expr *Pattern;
0168
0169 FoldExpandedConstraint(FoldOperatorKind K, NormalizedConstraint C,
0170 const Expr *Pattern)
0171 : Kind(K), Constraint(std::move(C)), Pattern(Pattern) {};
0172
0173 template <typename AtomicSubsumptionEvaluator>
0174 bool subsumes(const FoldExpandedConstraint &Other,
0175 const AtomicSubsumptionEvaluator &E) const;
0176
0177 static bool AreCompatibleForSubsumption(const FoldExpandedConstraint &A,
0178 const FoldExpandedConstraint &B);
0179 };
0180
0181 const NormalizedConstraint *getNormalizedAssociatedConstraints(
0182 Sema &S, NamedDecl *ConstrainedDecl,
0183 ArrayRef<const Expr *> AssociatedConstraints);
0184
0185 template <typename AtomicSubsumptionEvaluator>
0186 bool subsumes(const NormalForm &PDNF, const NormalForm &QCNF,
0187 const AtomicSubsumptionEvaluator &E) {
0188
0189
0190
0191
0192 for (const auto &Pi : PDNF) {
0193 for (const auto &Qj : QCNF) {
0194
0195
0196
0197
0198
0199 bool Found = false;
0200 for (NormalFormConstraint Pia : Pi) {
0201 for (NormalFormConstraint Qjb : Qj) {
0202 if (isa<FoldExpandedConstraint *>(Pia) &&
0203 isa<FoldExpandedConstraint *>(Qjb)) {
0204 if (cast<FoldExpandedConstraint *>(Pia)->subsumes(
0205 *cast<FoldExpandedConstraint *>(Qjb), E)) {
0206 Found = true;
0207 break;
0208 }
0209 } else if (isa<AtomicConstraint *>(Pia) &&
0210 isa<AtomicConstraint *>(Qjb)) {
0211 if (E(*cast<AtomicConstraint *>(Pia),
0212 *cast<AtomicConstraint *>(Qjb))) {
0213 Found = true;
0214 break;
0215 }
0216 }
0217 }
0218 if (Found)
0219 break;
0220 }
0221 if (!Found)
0222 return false;
0223 }
0224 }
0225 return true;
0226 }
0227
0228 template <typename AtomicSubsumptionEvaluator>
0229 bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, NamedDecl *DQ,
0230 ArrayRef<const Expr *> Q, bool &Subsumes,
0231 const AtomicSubsumptionEvaluator &E) {
0232
0233
0234
0235
0236 const NormalizedConstraint *PNormalized =
0237 getNormalizedAssociatedConstraints(S, DP, P);
0238 if (!PNormalized)
0239 return true;
0240 NormalForm PDNF = makeDNF(*PNormalized);
0241
0242 const NormalizedConstraint *QNormalized =
0243 getNormalizedAssociatedConstraints(S, DQ, Q);
0244 if (!QNormalized)
0245 return true;
0246 NormalForm QCNF = makeCNF(*QNormalized);
0247
0248 Subsumes = subsumes(PDNF, QCNF, E);
0249 return false;
0250 }
0251
0252 template <typename AtomicSubsumptionEvaluator>
0253 bool FoldExpandedConstraint::subsumes(
0254 const FoldExpandedConstraint &Other,
0255 const AtomicSubsumptionEvaluator &E) const {
0256
0257
0258
0259
0260
0261
0262 if (Kind != Other.Kind || !AreCompatibleForSubsumption(*this, Other))
0263 return false;
0264
0265 NormalForm PDNF = makeDNF(this->Constraint);
0266 NormalForm QCNF = makeCNF(Other.Constraint);
0267 return clang::subsumes(PDNF, QCNF, E);
0268 }
0269
0270 }
0271
0272 #endif