1 //===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides semantic analysis for C++ constraints and concepts.
12 //===----------------------------------------------------------------------===//
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"
30 struct AtomicConstraint {
31 const Expr *ConstraintExpr;
32 Optional<MutableArrayRef<TemplateArgumentLoc>> ParameterMapping;
34 AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
35 ConstraintExpr(ConstraintExpr) { };
37 bool hasMatchingParameterMapping(ASTContext &C,
38 const AtomicConstraint &Other) const {
39 if (!ParameterMapping != !Other.ParameterMapping)
41 if (!ParameterMapping)
43 if (ParameterMapping->size() != Other.ParameterMapping->size())
46 for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
47 llvm::FoldingSetNodeID IDA, IDB;
48 C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
50 C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
58 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 [...]
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 [...]
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)
74 // Check that the parameter lists are identical
75 return hasMatchingParameterMapping(C, Other);
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 {
85 enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
87 using CompoundConstraint = llvm::PointerIntPair<
88 std::pair<NormalizedConstraint, NormalizedConstraint> *, 1,
89 CompoundConstraintKind>;
91 llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint;
93 NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
94 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}} { };
100 NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other) {
101 if (Other.isAtomic()) {
102 Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint());
104 Constraint = CompoundConstraint(
105 new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{
106 NormalizedConstraint(C, Other.getLHS()),
107 NormalizedConstraint(C, Other.getRHS())},
108 Other.getCompoundKind());
111 NormalizedConstraint(NormalizedConstraint &&Other):
112 Constraint(Other.Constraint) {
113 Other.Constraint = nullptr;
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);
124 CompoundConstraintKind getCompoundKind() const {
125 assert(!isAtomic() && "getCompoundKind called on atomic constraint.");
126 return Constraint.get<CompoundConstraint>().getInt();
129 bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); }
131 NormalizedConstraint &getLHS() const {
132 assert(!isAtomic() && "getLHS called on atomic constraint.");
133 return Constraint.get<CompoundConstraint>().getPointer()->first;
136 NormalizedConstraint &getRHS() const {
137 assert(!isAtomic() && "getRHS called on atomic constraint.");
138 return Constraint.get<CompoundConstraint>().getPointer()->second;
141 AtomicConstraint *getAtomicConstraint() const {
143 "getAtomicConstraint called on non-atomic constraint.");
144 return Constraint.get<AtomicConstraint *>();
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);
156 #endif //LLVM_CLANG_SEMA_SEMACONCEPT_H