Home | History | Annotate | Line # | Download | only in Sema
      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 
     34   AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
     35       ConstraintExpr(ConstraintExpr) { };
     36 
     37   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 
     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 [...]
     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 
     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}} { };
     99 
    100   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   }
    111   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 
    124   CompoundConstraintKind getCompoundKind() const {
    125     assert(!isAtomic() && "getCompoundKind called on atomic constraint.");
    126     return Constraint.get<CompoundConstraint>().getInt();
    127   }
    128 
    129   bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); }
    130 
    131   NormalizedConstraint &getLHS() const {
    132     assert(!isAtomic() && "getLHS called on atomic constraint.");
    133     return Constraint.get<CompoundConstraint>().getPointer()->first;
    134   }
    135 
    136   NormalizedConstraint &getRHS() const {
    137     assert(!isAtomic() && "getRHS called on atomic constraint.");
    138     return Constraint.get<CompoundConstraint>().getPointer()->second;
    139   }
    140 
    141   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