xref: /openbsd-src/gnu/llvm/clang/include/clang/Sema/SemaConcept.h (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===//
2e5dd7070Spatrick //
3*12c85518Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*12c85518Srobert // See https://llvm.org/LICENSE.txt for license information.
5*12c85518Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick ///
9e5dd7070Spatrick //  This file provides semantic analysis for C++ constraints and concepts.
10e5dd7070Spatrick ///
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H
14e5dd7070Spatrick #define LLVM_CLANG_SEMA_SEMACONCEPT_H
15e5dd7070Spatrick #include "clang/AST/ASTConcept.h"
16e5dd7070Spatrick #include "clang/AST/ASTContext.h"
17e5dd7070Spatrick #include "clang/AST/Expr.h"
18e5dd7070Spatrick #include "clang/AST/DeclTemplate.h"
19e5dd7070Spatrick #include "clang/Basic/SourceLocation.h"
20e5dd7070Spatrick #include "llvm/ADT/PointerUnion.h"
21e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
22*12c85518Srobert #include <optional>
23e5dd7070Spatrick #include <string>
24e5dd7070Spatrick #include <utility>
25e5dd7070Spatrick 
26e5dd7070Spatrick namespace clang {
27e5dd7070Spatrick class Sema;
28e5dd7070Spatrick 
29e5dd7070Spatrick struct AtomicConstraint {
30e5dd7070Spatrick   const Expr *ConstraintExpr;
31*12c85518Srobert   std::optional<ArrayRef<TemplateArgumentLoc>> ParameterMapping;
32e5dd7070Spatrick 
AtomicConstraintAtomicConstraint33e5dd7070Spatrick   AtomicConstraint(Sema &S, const Expr *ConstraintExpr) :
34e5dd7070Spatrick       ConstraintExpr(ConstraintExpr) { };
35e5dd7070Spatrick 
hasMatchingParameterMappingAtomicConstraint36e5dd7070Spatrick   bool hasMatchingParameterMapping(ASTContext &C,
37e5dd7070Spatrick                                    const AtomicConstraint &Other) const {
38e5dd7070Spatrick     if (!ParameterMapping != !Other.ParameterMapping)
39e5dd7070Spatrick       return false;
40e5dd7070Spatrick     if (!ParameterMapping)
41e5dd7070Spatrick       return true;
42e5dd7070Spatrick     if (ParameterMapping->size() != Other.ParameterMapping->size())
43e5dd7070Spatrick       return false;
44e5dd7070Spatrick 
45e5dd7070Spatrick     for (unsigned I = 0, S = ParameterMapping->size(); I < S; ++I) {
46e5dd7070Spatrick       llvm::FoldingSetNodeID IDA, IDB;
47e5dd7070Spatrick       C.getCanonicalTemplateArgument((*ParameterMapping)[I].getArgument())
48e5dd7070Spatrick           .Profile(IDA, C);
49e5dd7070Spatrick       C.getCanonicalTemplateArgument((*Other.ParameterMapping)[I].getArgument())
50e5dd7070Spatrick           .Profile(IDB, C);
51e5dd7070Spatrick       if (IDA != IDB)
52e5dd7070Spatrick         return false;
53e5dd7070Spatrick     }
54e5dd7070Spatrick     return true;
55e5dd7070Spatrick   }
56e5dd7070Spatrick 
subsumesAtomicConstraint57e5dd7070Spatrick   bool subsumes(ASTContext &C, const AtomicConstraint &Other) const {
58e5dd7070Spatrick     // C++ [temp.constr.order] p2
59e5dd7070Spatrick     //   - an atomic constraint A subsumes another atomic constraint B
60e5dd7070Spatrick     //     if and only if the A and B are identical [...]
61e5dd7070Spatrick     //
62e5dd7070Spatrick     // C++ [temp.constr.atomic] p2
63e5dd7070Spatrick     //   Two atomic constraints are identical if they are formed from the
64e5dd7070Spatrick     //   same expression and the targets of the parameter mappings are
65e5dd7070Spatrick     //   equivalent according to the rules for expressions [...]
66e5dd7070Spatrick 
67e5dd7070Spatrick     // We do not actually substitute the parameter mappings into the
68e5dd7070Spatrick     // constraint expressions, therefore the constraint expressions are
69e5dd7070Spatrick     // the originals, and comparing them will suffice.
70e5dd7070Spatrick     if (ConstraintExpr != Other.ConstraintExpr)
71e5dd7070Spatrick       return false;
72e5dd7070Spatrick 
73e5dd7070Spatrick     // Check that the parameter lists are identical
74e5dd7070Spatrick     return hasMatchingParameterMapping(C, Other);
75e5dd7070Spatrick   }
76e5dd7070Spatrick };
77e5dd7070Spatrick 
78e5dd7070Spatrick /// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
79e5dd7070Spatrick /// either an atomic constraint, a conjunction of normalized constraints or a
80e5dd7070Spatrick /// disjunction of normalized constraints.
81e5dd7070Spatrick struct NormalizedConstraint {
82e5dd7070Spatrick   friend class Sema;
83e5dd7070Spatrick 
84e5dd7070Spatrick   enum CompoundConstraintKind { CCK_Conjunction, CCK_Disjunction };
85e5dd7070Spatrick 
86e5dd7070Spatrick   using CompoundConstraint = llvm::PointerIntPair<
87e5dd7070Spatrick       std::pair<NormalizedConstraint, NormalizedConstraint> *, 1,
88e5dd7070Spatrick       CompoundConstraintKind>;
89e5dd7070Spatrick 
90e5dd7070Spatrick   llvm::PointerUnion<AtomicConstraint *, CompoundConstraint> Constraint;
91e5dd7070Spatrick 
NormalizedConstraintNormalizedConstraint92e5dd7070Spatrick   NormalizedConstraint(AtomicConstraint *C): Constraint{C} { };
NormalizedConstraintNormalizedConstraint93e5dd7070Spatrick   NormalizedConstraint(ASTContext &C, NormalizedConstraint LHS,
94e5dd7070Spatrick                        NormalizedConstraint RHS, CompoundConstraintKind Kind)
95e5dd7070Spatrick       : Constraint{CompoundConstraint{
96e5dd7070Spatrick             new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{
97e5dd7070Spatrick                 std::move(LHS), std::move(RHS)}, Kind}} { };
98e5dd7070Spatrick 
NormalizedConstraintNormalizedConstraint99e5dd7070Spatrick   NormalizedConstraint(ASTContext &C, const NormalizedConstraint &Other) {
100e5dd7070Spatrick     if (Other.isAtomic()) {
101e5dd7070Spatrick       Constraint = new (C) AtomicConstraint(*Other.getAtomicConstraint());
102e5dd7070Spatrick     } else {
103e5dd7070Spatrick       Constraint = CompoundConstraint(
104e5dd7070Spatrick           new (C) std::pair<NormalizedConstraint, NormalizedConstraint>{
105e5dd7070Spatrick               NormalizedConstraint(C, Other.getLHS()),
106e5dd7070Spatrick               NormalizedConstraint(C, Other.getRHS())},
107e5dd7070Spatrick               Other.getCompoundKind());
108e5dd7070Spatrick     }
109e5dd7070Spatrick   }
NormalizedConstraintNormalizedConstraint110e5dd7070Spatrick   NormalizedConstraint(NormalizedConstraint &&Other):
111e5dd7070Spatrick       Constraint(Other.Constraint) {
112e5dd7070Spatrick     Other.Constraint = nullptr;
113e5dd7070Spatrick   }
114e5dd7070Spatrick   NormalizedConstraint &operator=(const NormalizedConstraint &Other) = delete;
115e5dd7070Spatrick   NormalizedConstraint &operator=(NormalizedConstraint &&Other) {
116e5dd7070Spatrick     if (&Other != this) {
117e5dd7070Spatrick       NormalizedConstraint Temp(std::move(Other));
118e5dd7070Spatrick       std::swap(Constraint, Temp.Constraint);
119e5dd7070Spatrick     }
120e5dd7070Spatrick     return *this;
121e5dd7070Spatrick   }
122e5dd7070Spatrick 
getCompoundKindNormalizedConstraint123e5dd7070Spatrick   CompoundConstraintKind getCompoundKind() const {
124e5dd7070Spatrick     assert(!isAtomic() && "getCompoundKind called on atomic constraint.");
125e5dd7070Spatrick     return Constraint.get<CompoundConstraint>().getInt();
126e5dd7070Spatrick   }
127e5dd7070Spatrick 
isAtomicNormalizedConstraint128e5dd7070Spatrick   bool isAtomic() const { return Constraint.is<AtomicConstraint *>(); }
129e5dd7070Spatrick 
getLHSNormalizedConstraint130e5dd7070Spatrick   NormalizedConstraint &getLHS() const {
131e5dd7070Spatrick     assert(!isAtomic() && "getLHS called on atomic constraint.");
132e5dd7070Spatrick     return Constraint.get<CompoundConstraint>().getPointer()->first;
133e5dd7070Spatrick   }
134e5dd7070Spatrick 
getRHSNormalizedConstraint135e5dd7070Spatrick   NormalizedConstraint &getRHS() const {
136e5dd7070Spatrick     assert(!isAtomic() && "getRHS called on atomic constraint.");
137e5dd7070Spatrick     return Constraint.get<CompoundConstraint>().getPointer()->second;
138e5dd7070Spatrick   }
139e5dd7070Spatrick 
getAtomicConstraintNormalizedConstraint140e5dd7070Spatrick   AtomicConstraint *getAtomicConstraint() const {
141e5dd7070Spatrick     assert(isAtomic() &&
142e5dd7070Spatrick            "getAtomicConstraint called on non-atomic constraint.");
143e5dd7070Spatrick     return Constraint.get<AtomicConstraint *>();
144e5dd7070Spatrick   }
145e5dd7070Spatrick 
146e5dd7070Spatrick private:
147*12c85518Srobert   static std::optional<NormalizedConstraint>
148e5dd7070Spatrick   fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E);
149*12c85518Srobert   static std::optional<NormalizedConstraint>
150e5dd7070Spatrick   fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E);
151e5dd7070Spatrick };
152e5dd7070Spatrick 
153e5dd7070Spatrick } // clang
154e5dd7070Spatrick 
155e5dd7070Spatrick #endif // LLVM_CLANG_SEMA_SEMACONCEPT_H
156