1 //===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 // This file provides semantic analysis for C++ constraints and concepts. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H 15 #define LLVM_CLANG_SEMA_SEMACONCEPT_H 16 #include "clang/AST/ASTConcept.h" 17 #include "clang/AST/ASTContext.h" 18 #include "clang/AST/Expr.h" 19 #include "clang/AST/DeclTemplate.h" 20 #include "clang/Basic/SourceLocation.h" 21 #include "llvm/ADT/PointerUnion.h" 22 #include "llvm/ADT/Optional.h" 23 #include "llvm/ADT/SmallVector.h" 24 #include <string> 25 #include <utility> 26 27 namespace clang { 28 class Sema; 29 30 struct AtomicConstraint { 31 const Expr *ConstraintExpr; 32 Optional<MutableArrayRef<TemplateArgumentLoc>> ParameterMapping; 33 AtomicConstraintAtomicConstraint34 AtomicConstraint(Sema &S, const Expr *ConstraintExpr) : 35 ConstraintExpr(ConstraintExpr) { }; 36 hasMatchingParameterMappingAtomicConstraint37 bool hasMatchingParameterMapping(ASTContext &C, 38 const AtomicConstraint &Other) const { 39 if (!ParameterMapping != !Other.ParameterMapping) 40 return false; 41 if (!ParameterMapping) 42 return true; 43 if (ParameterMapping->size() != Other.ParameterMapping->size()) 44 return false; 45 46 for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) { 47 llvm::FoldingSetNodeID IDA, IDB; 48 C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) 49 .Profile(IDA, C); 50 C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument()) 51 .Profile(IDB, C); 52 if (IDA != IDB) 53 return false; 54 } 55 return true; 56 } 57 subsumesAtomicConstraint58 bool subsumes(ASTContext &C, const AtomicConstraint &Other) const { 59 // C++ [temp.constr.order] p2 60 // - an atomic constraint A subsumes another atomic constraint B 61 // if and only if the A and B are identical [...] 62 // 63 // C++ [temp.constr.atomic] p2 64 // Two atomic constraints are identical if they are formed from the 65 // same expression and the targets of the parameter mappings are 66 // equivalent according to the rules for expressions [...] 67 68 // We do not actually substitute the parameter mappings into the 69 // constraint expressions, therefore the constraint expressions are 70 // the originals, and comparing them will suffice. 71 if (ConstraintExpr != Other.ConstraintExpr) 72 return false; 73 74 // Check that the parameter lists are identical 75 return hasMatchingParameterMapping(C, Other); 76 } 77 }; 78 79 /// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is 80 /// either an atomic constraint, a conjunction of normalized constraints or a 81 /// disjunction of normalized constraints. 82 struct NormalizedConstraint { 83 friend class Sema; 84 85 enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction }; 86 87 using CompoundConstraint = llvm::PointerIntPair< 88 std::pair<NormalizedConstraint, NormalizedConstraint> *, 1, 89 CompoundConstraintKind>; 90 91 llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint; 92 NormalizedConstraintNormalizedConstraint93 NormalizedConstraint(AtomicConstraint *C): Constraint{C} { }; NormalizedConstraintNormalizedConstraint94 NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS, 95 NormalizedConstraint RHS, CompoundConstraintKind Kind) 96 : Constraint{CompoundConstraint{ 97 new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{ 98 std::move(LHS), std::move(RHS)}, Kind}} { }; 99 NormalizedConstraintNormalizedConstraint100 NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other) { 101 if (Other.isAtomic()) { 102 Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint()); 103 } else { 104 Constraint = CompoundConstraint( 105 new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{ 106 NormalizedConstraint(C, Other.getLHS()), 107 NormalizedConstraint(C, Other.getRHS())}, 108 Other.getCompoundKind()); 109 } 110 } NormalizedConstraintNormalizedConstraint111 NormalizedConstraint(NormalizedConstraint &&Other): 112 Constraint(Other.Constraint) { 113 Other.Constraint = nullptr; 114 } 115 NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete; 116 NormalizedConstraint &operator=(NormalizedConstraint &&Other) { 117 if (&Other != this) { 118 NormalizedConstraint Temp(std::move(Other)); 119 std::swap(Constraint, Temp.Constraint); 120 } 121 return *this; 122 } 123 getCompoundKindNormalizedConstraint124 CompoundConstraintKind getCompoundKind() const { 125 assert(!isAtomic() && "getCompoundKind called on atomic constraint."); 126 return Constraint.get<CompoundConstraint>().getInt(); 127 } 128 isAtomicNormalizedConstraint129 bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); } 130 getLHSNormalizedConstraint131 NormalizedConstraint &getLHS() const { 132 assert(!isAtomic() && "getLHS called on atomic constraint."); 133 return Constraint.get<CompoundConstraint>().getPointer()->first; 134 } 135 getRHSNormalizedConstraint136 NormalizedConstraint &getRHS() const { 137 assert(!isAtomic() && "getRHS called on atomic constraint."); 138 return Constraint.get<CompoundConstraint>().getPointer()->second; 139 } 140 getAtomicConstraintNormalizedConstraint141 AtomicConstraint *getAtomicConstraint() const { 142 assert(isAtomic() && 143 "getAtomicConstraint called on non-atomic constraint."); 144 return Constraint.get<AtomicConstraint *>(); 145 } 146 147 private: 148 static Optional<NormalizedConstraint> 149 fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E); 150 static Optional<NormalizedConstraint> 151 fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E); 152 }; 153 154 } // clang 155 156 #endif //LLVM_CLANG_SEMA_SEMACONCEPT_H 157