//===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// // This file provides semantic analysis for C++ constraints and concepts. /// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H #define LLVM_CLANG_SEMA_SEMACONCEPT_H #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include #include namespace clang { class Sema; struct AtomicConstraint { const Expr *ConstraintExpr; Optional> ParameterMapping; AtomicConstraint(Sema &S, const Expr *ConstraintExpr) : ConstraintExpr(ConstraintExpr) { }; bool hasMatchingParameterMapping(ASTContext &C, const AtomicConstraint &Other) const { if (!ParameterMapping != !Other.ParameterMapping) return false; if (!ParameterMapping) return true; if (ParameterMapping->size() != Other.ParameterMapping->size()) return false; for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) if (!C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument()) .structurallyEquals(C.getCanonicalTemplateArgument( (*Other.ParameterMapping)[I].getArgument()))) return false; return true; } bool subsumes(ASTContext &C, const AtomicConstraint &Other) const { // C++ [temp.constr.order] p2 // - an atomic constraint A subsumes another atomic constraint B // if and only if the A and B are identical [...] // // C++ [temp.constr.atomic] p2 // Two atomic constraints are identical if they are formed from the // same expression and the targets of the parameter mappings are // equivalent according to the rules for expressions [...] // We do not actually substitute the parameter mappings into the // constraint expressions, therefore the constraint expressions are // the originals, and comparing them will suffice. if (ConstraintExpr != Other.ConstraintExpr) return false; // Check that the parameter lists are identical return hasMatchingParameterMapping(C, Other); } }; /// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is /// either an atomic constraint, a conjunction of normalized constraints or a /// disjunction of normalized constraints. struct NormalizedConstraint { friend class Sema; enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction }; using CompoundConstraint = llvm::PointerIntPair< std::pair *, 1, CompoundConstraintKind>; llvm::PointerUnion Constraint; NormalizedConstraint(AtomicConstraint *C): Constraint{C} { }; NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS, NormalizedConstraint RHS, CompoundConstraintKind Kind) : Constraint{CompoundConstraint{ new (C) std::pair{ std::move(LHS), std::move(RHS)}, Kind}} { }; NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other) { if (Other.isAtomic()) { Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint()); } else { Constraint = CompoundConstraint( new (C) std::pair{ NormalizedConstraint(C, Other.getLHS()), NormalizedConstraint(C, Other.getRHS())}, Other.getCompoundKind()); } } NormalizedConstraint(NormalizedConstraint &&Other): Constraint(Other.Constraint) { Other.Constraint = nullptr; } NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete; NormalizedConstraint &operator=(NormalizedConstraint &&Other) { if (&Other != this) { NormalizedConstraint Temp(std::move(Other)); std::swap(Constraint, Temp.Constraint); } return *this; } CompoundConstraintKind getCompoundKind() const { assert(!isAtomic() && "getCompoundKind called on atomic constraint."); return Constraint.get().getInt(); } bool isAtomic() const { return Constraint.is(); } NormalizedConstraint &getLHS() const { assert(!isAtomic() && "getLHS called on atomic constraint."); return Constraint.get().getPointer()->first; } NormalizedConstraint &getRHS() const { assert(!isAtomic() && "getRHS called on atomic constraint."); return Constraint.get().getPointer()->second; } AtomicConstraint *getAtomicConstraint() const { assert(isAtomic() && "getAtomicConstraint called on non-atomic constraint."); return Constraint.get(); } private: static Optional fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef E); static Optional fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E); }; } // clang #endif //LLVM_CLANG_SEMA_SEMACONCEPT_H