Thanks to visit codestin.com
Credit goes to clang.llvm.org

clang 22.0.0git
SemaConcept.h
Go to the documentation of this file.
1//===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9// This file provides semantic analysis for C++ constraints and concepts.
10///
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_SEMA_SEMACONCEPT_H
14#define LLVM_CLANG_SEMA_SEMACONCEPT_H
18#include "clang/AST/Expr.h"
22#include "llvm/ADT/FoldingSet.h"
23#include "llvm/ADT/STLFunctionalExtras.h"
24#include "llvm/ADT/SmallBitVector.h"
25#include "llvm/ADT/SmallVector.h"
26#include <optional>
27#include <utility>
28
29namespace clang {
30class Sema;
32
33/// \brief A normalized constraint, as defined in C++ [temp.constr.normal], is
34/// either an atomic constraint, a conjunction of normalized constraints or a
35/// disjunction of normalized constraints.
37
38 enum class ConstraintKind : unsigned char {
39 Atomic = 0,
43 };
44
49 enum class FoldOperatorKind : unsigned char { And, Or };
50
51 using OccurenceList = llvm::SmallBitVector;
52
53protected:
55 llvm::PointerUnion<const Expr *, const ConceptReference *>;
56
58 // Kind is the first member of all union members,
59 // as we rely on their initial common sequence.
60 LLVM_PREFERRED_TYPE(ConstraintKind)
62 unsigned Placeholder : 1;
63 unsigned PackSubstitutionIndex : 26;
64 // Indexes, IndexesForSubsumption, and Args are part of the common initial
65 // sequences of constraints that do have a mapping.
66
67 // Indexes of the parameters used in a constraint expression.
69 // Indexes of the parameters named directly in a constraint expression.
70 // FIXME: we should try to reduce the size of this struct?
72
77 };
78
93
96
97 // Only used for parameter mapping.
99 };
100
102 LLVM_PREFERRED_TYPE(ConstraintKind)
104 LLVM_PREFERRED_TYPE(CompoundConstraintKind)
105 unsigned CCK : 1;
108 };
109
110 union {
115 };
116
119 Atomic.Indexes.llvm::SmallBitVector::~SmallBitVector();
120 }
121
122 NormalizedConstraint(const Expr *ConstraintExpr,
123 const NamedDecl *ConstraintDecl,
124 UnsignedOrNone PackIndex)
125 : Atomic{llvm::to_underlying(ConstraintKind::Atomic),
126 /*Placeholder=*/0,
127 PackIndex.toInternalRepresentation(),
128 /*Indexes=*/{},
129 /*IndexesForSubsumption=*/{},
130 /*Args=*/nullptr,
131 /*ParamList=*/nullptr,
132 ConstraintExpr,
133 ConstraintDecl} {}
134
136 NormalizedConstraint *Constraint,
138 : FoldExpanded{llvm::to_underlying(ConstraintKind::FoldExpanded),
139 llvm::to_underlying(OpKind),
140 /*Placeholder=*/0,
141 /*Indexes=*/{},
142 /*IndexesForSubsumption=*/{},
143 /*Args=*/nullptr,
144 /*ParamList=*/nullptr,
145 Pattern,
147 Constraint} {}
148
151 NormalizedConstraint *SubConstraint,
152 const ConceptSpecializationExpr *CSE,
153 UnsignedOrNone PackIndex)
154 : ConceptId{{llvm::to_underlying(ConstraintKind::ConceptId),
155 /*Placeholder=*/0, PackIndex.toInternalRepresentation(),
156 /*Indexes=*/{},
157 /*IndexesForSubsumption=*/{},
158 /*Args=*/nullptr, /*ParamList=*/nullptr, ConceptId,
160 SubConstraint,
161 CSE} {}
162
165 : Compound{llvm::to_underlying(ConstraintKind::Compound),
166 llvm::to_underlying(CCK), LHS, RHS} {}
167
168 bool hasParameterMapping() const {
169 // compound constraints do not have a mapping
170 // and Args is not part of their common initial sequence.
171 return getKind() != ConstraintKind::Compound && Atomic.Args != nullptr;
172 }
173
175 assert(hasParameterMapping() && "This constraint has no parameter mapping");
176 return Atomic.Indexes;
177 }
178
180 assert(hasParameterMapping() && "This constraint has no parameter mapping");
181 return Atomic.IndexesForSubsumption;
182 }
183
185 return {Atomic.Args, Atomic.Indexes.count()};
186 }
187
189 return Atomic.ParamList;
190 }
191
193 OccurenceList IndexesForSubsumption,
195 TemplateParameterList *ParamList) {
197 assert(Indexes.count() == Args.size());
198 assert(IndexesForSubsumption.size() == Indexes.size());
199 assert((Indexes | IndexesForSubsumption) == Indexes);
200
201 Atomic.IndexesForSubsumption = std::move(IndexesForSubsumption);
202 Atomic.Indexes = std::move(Indexes);
203 Atomic.Args = Args.data();
204 Atomic.ParamList = ParamList;
205 }
206
208 const NormalizedConstraint &Other) const {
210
211 if (hasParameterMapping() != Other.hasParameterMapping())
212 return false;
213 if (!hasParameterMapping())
214 return true;
215
216 llvm::ArrayRef<TemplateArgumentLoc> ParameterMapping =
218 llvm::ArrayRef<TemplateArgumentLoc> OtherParameterMapping =
219 Other.getParameterMapping();
220
222 const OccurenceList &OtherIndexes =
223 Other.mappingOccurenceListForSubsumption();
224
225 if (ParameterMapping.size() != OtherParameterMapping.size())
226 return false;
227 for (unsigned I = 0, S = ParameterMapping.size(); I < S; ++I) {
228 if (Indexes[I] != OtherIndexes[I])
229 return false;
230 if (!Indexes[I])
231 continue;
232 llvm::FoldingSetNodeID IDA, IDB;
233 C.getCanonicalTemplateArgument(ParameterMapping[I].getArgument())
234 .Profile(IDA, C);
235 C.getCanonicalTemplateArgument(OtherParameterMapping[I].getArgument())
236 .Profile(IDB, C);
237 if (IDA != IDB)
238 return false;
239 }
240 return true;
241 }
242
243public:
245 return static_cast<ConstraintKind>(Atomic.Kind);
246 }
247
249 switch (getKind()) {
251 return cast<const Expr *>(Atomic.ConstraintExpr)->getBeginLoc();
253 return cast<const ConceptReference *>(Atomic.ConstraintExpr)
254 ->getBeginLoc();
256 return Compound.LHS->getBeginLoc();
258 return FoldExpanded.Pattern->getBeginLoc();
259 }
260 llvm_unreachable("Unknown ConstraintKind enum");
261 }
262
264 switch (getKind()) {
266 return cast<const Expr *>(Atomic.ConstraintExpr)->getEndLoc();
268 return cast<const ConceptReference *>(Atomic.ConstraintExpr)->getEndLoc();
270 return Compound.RHS->getEndLoc();
272 return FoldExpanded.Pattern->getEndLoc();
273 }
274 llvm_unreachable("Unknown ConstraintKind enum");
275 }
276
278
279private:
280 friend class Sema;
281 static NormalizedConstraint *
282 fromAssociatedConstraints(Sema &S, const NamedDecl *D,
284 static NormalizedConstraint *fromConstraintExpr(Sema &S, const NamedDecl *D,
285 const Expr *E,
286 UnsignedOrNone SubstIndex);
287};
288
289class CompoundConstraint : public NormalizedConstraint {
291
292public:
293 static CompoundConstraint *Create(ASTContext &Ctx, NormalizedConstraint *LHS,
295 NormalizedConstraint *RHS) {
296 return new (Ctx) CompoundConstraint(LHS, CCK, RHS);
297 }
298
300 NormalizedConstraint *LHS,
301 NormalizedConstraint *RHS) {
302 return new (Ctx) CompoundConstraint(LHS, CCK_Conjunction, RHS);
303 }
304
305 const NormalizedConstraint &getLHS() const { return *Compound.LHS; }
306
307 NormalizedConstraint &getLHS() { return *Compound.LHS; }
308
309 const NormalizedConstraint &getRHS() const { return *Compound.RHS; }
310
311 NormalizedConstraint &getRHS() { return *Compound.RHS; }
312
314 return static_cast<CompoundConstraintKind>(Compound.CCK);
315 }
316};
317
338
341 NormalizedConstraintWithParamMapping;
342
343public:
344 static AtomicConstraint *Create(ASTContext &Ctx, const Expr *ConstraintExpr,
345 const NamedDecl *ConstraintDecl,
346 UnsignedOrNone PackIndex) {
347 return new (Ctx)
348 AtomicConstraint(ConstraintExpr, ConstraintDecl, PackIndex);
349 }
350
351 const Expr *getConstraintExpr() const {
352 return cast<const Expr *>(Atomic.ConstraintExpr);
353 }
354};
355
358 NormalizedConstraintWithParamMapping;
359
360public:
361 static FoldExpandedConstraint *Create(ASTContext &Ctx, const Expr *Pattern,
362 const NamedDecl *ConstraintDecl,
363 FoldOperatorKind OpKind,
364 NormalizedConstraint *Constraint) {
365 return new (Ctx)
366 FoldExpandedConstraint(Pattern, OpKind, Constraint, ConstraintDecl);
367 }
368
370
372 return static_cast<FoldOperatorKind>(FoldExpanded.FoldOperator);
373 }
374
375 const Expr *getPattern() const { return FoldExpanded.Pattern; }
376
378 return *FoldExpanded.Constraint;
379 }
380
382 return *FoldExpanded.Constraint;
383 }
384
386 const FoldExpandedConstraint &B);
387};
388
391 NormalizedConstraintWithParamMapping;
392
393public:
394 static ConceptIdConstraint *
396 NormalizedConstraint *SubConstraint, const NamedDecl *ConstraintDecl,
397 const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex) {
398 return new (Ctx) ConceptIdConstraint(ConceptId, ConstraintDecl,
399 SubConstraint, CSE, PackIndex);
400 }
401
405
407 return cast<const ConceptReference *>(ConceptId.ConstraintExpr);
408 }
409
411 return *ConceptId.Sub;
412 }
413
415};
416
421
422/// \brief SubsumptionChecker establishes subsumption
423/// between two set of constraints.
425public:
426 using SubsumptionCallable = llvm::function_ref<bool(
427 const AtomicConstraint &, const AtomicConstraint &)>;
428
429 SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable = {});
430
431 std::optional<bool> Subsumes(const NamedDecl *DP,
433 const NamedDecl *DQ,
435
436 bool Subsumes(const NormalizedConstraint *P, const NormalizedConstraint *Q);
437
438private:
439 Sema &SemaRef;
441
442 // Each Literal has a unique value that is enough to establish
443 // its identity.
444 // Some constraints (fold expended) require special subsumption
445 // handling logic beyond comparing values, so we store a flag
446 // to let us quickly dispatch to each kind of variable.
447 struct Literal {
448 enum Kind { Atomic, FoldExpanded };
449
450 unsigned Value : 16;
451 LLVM_PREFERRED_TYPE(Kind)
452 unsigned Kind : 1;
453
454 bool operator==(const Literal &Other) const { return Value == Other.Value; }
455 bool operator<(const Literal &Other) const { return Value < Other.Value; }
456 };
457 using Clause = llvm::SmallVector<Literal>;
458 using Formula = llvm::SmallVector<Clause, 5>;
459
460 struct CNFFormula : Formula {
461 static constexpr auto Kind = NormalizedConstraint::CCK_Conjunction;
462 using Formula::Formula;
463 };
464 struct DNFFormula : Formula {
465 static constexpr auto Kind = NormalizedConstraint::CCK_Disjunction;
466 using Formula::Formula;
467 };
468
469 struct MappedAtomicConstraint {
470 const AtomicConstraint *Constraint;
471 Literal ID;
472 };
473
474 struct FoldExpendedConstraintKey {
476 const AtomicConstraint *Constraint;
477 Literal ID;
478 };
479
480 llvm::DenseMap<const Expr *, llvm::SmallDenseMap<llvm::FoldingSetNodeID,
481 MappedAtomicConstraint>>
482 AtomicMap;
483
484 llvm::DenseMap<const Expr *, std::vector<FoldExpendedConstraintKey>> FoldMap;
485
486 // A map from a literal to a corresponding associated constraint.
487 // We do not have enough bits left for a pointer union here :(
488 llvm::DenseMap<uint16_t, const void *> ReverseMap;
489
490 // Fold expanded constraints ask us to recursively establish subsumption.
491 // This caches the result.
492 llvm::SmallDenseMap<
493 std::pair<const FoldExpandedConstraint *, const FoldExpandedConstraint *>,
494 bool>
495 FoldSubsumptionCache;
496
497 // Each <atomic, fold expanded constraint> is represented as a single ID.
498 // This is intentionally kept small we can't handle a large number of
499 // constraints anyway.
500 uint16_t NextID;
501
502 bool Subsumes(const DNFFormula &P, const CNFFormula &Q);
503 bool Subsumes(Literal A, Literal B);
504 bool Subsumes(const FoldExpandedConstraint *A,
505 const FoldExpandedConstraint *B);
506 bool DNFSubsumes(const Clause &P, const Clause &Q);
507
508 CNFFormula CNF(const NormalizedConstraint &C);
509 DNFFormula DNF(const NormalizedConstraint &C);
510
511 template <typename FormulaType>
512 FormulaType Normalize(const NormalizedConstraint &C);
513 void AddUniqueClauseToFormula(Formula &F, Clause C);
514
515 Literal find(const AtomicConstraint *);
516 Literal find(const FoldExpandedConstraint *);
517
518 uint16_t getNewLiteralId();
519};
520
521} // namespace clang
522
523#endif // LLVM_CLANG_SEMA_SEMACONCEPT_H
This file provides AST data structures related to concepts.
Defines the clang::ASTContext interface.
static Decl::Kind getKind(const Decl *D)
Defines the C++ template declaration subclasses.
Defines Expressions and AST nodes for C++2a concepts.
Defines the clang::SourceLocation class and associated facilities.
static const TemplateArgument & getArgument(const TemplateArgument &A)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
const Expr * getConstraintExpr() const
static AtomicConstraint * Create(ASTContext &Ctx, const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl, UnsignedOrNone PackIndex)
const NormalizedConstraint & getLHS() const
NormalizedConstraint & getLHS()
NormalizedConstraint & getRHS()
static CompoundConstraint * CreateConjunction(ASTContext &Ctx, NormalizedConstraint *LHS, NormalizedConstraint *RHS)
CompoundConstraintKind getCompoundKind() const
const NormalizedConstraint & getRHS() const
static CompoundConstraint * Create(ASTContext &Ctx, NormalizedConstraint *LHS, CompoundConstraintKind CCK, NormalizedConstraint *RHS)
const NormalizedConstraint & getNormalizedConstraint() const
const ConceptSpecializationExpr * getConceptSpecializationExpr() const
static ConceptIdConstraint * Create(ASTContext &Ctx, const ConceptReference *ConceptId, NormalizedConstraint *SubConstraint, const NamedDecl *ConstraintDecl, const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex)
NormalizedConstraint & getNormalizedConstraint()
const ConceptReference * getConceptId() const
A reference to a concept and its template args, as it appears in the code.
Definition ASTConcept.h:130
Represents the specialization of a concept - evaluates to a prvalue of type bool.
The result of a constraint satisfaction check, containing the necessary information to diagnose an un...
Definition ASTConcept.h:47
This represents one expression.
Definition Expr.h:112
static bool AreCompatibleForSubsumption(const FoldExpandedConstraint &A, const FoldExpandedConstraint &B)
FoldOperatorKind getFoldOperator() const
NormalizedConstraint & getNormalizedPattern()
const Expr * getPattern() const
static FoldExpandedConstraint * Create(ASTContext &Ctx, const Expr *Pattern, const NamedDecl *ConstraintDecl, FoldOperatorKind OpKind, NormalizedConstraint *Constraint)
const NormalizedConstraint & getNormalizedPattern() const
Data structure that captures multiple levels of template argument lists for use in template instantia...
Definition Template.h:76
This represents a decl that may have a name.
Definition Decl.h:274
UnsignedOrNone getPackSubstitutionIndex() const
const NamedDecl * getConstraintDecl() const
NormalizedConstraint(const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl, UnsignedOrNone PackIndex)
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:854
Encodes a location in the source.
A trivial tuple used to represent a source range.
std::optional< bool > Subsumes(const NamedDecl *DP, ArrayRef< AssociatedConstraint > P, const NamedDecl *DQ, ArrayRef< AssociatedConstraint > Q)
SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable={})
llvm::function_ref< bool( const AtomicConstraint &, const AtomicConstraint &)> SubsumptionCallable
Location wrapper for a TemplateArgument.
Stores a list of template parameters for a TemplateDecl and its derived classes.
#define bool
Definition gpuintrin.h:32
uint32_t Literal
Literals are represented as positive integers.
Definition CNFFormula.h:35
The JSON file list parser is used to communicate input to InstallAPI.
U cast(CodeGen::Address addr)
Definition Address.h:327
ActionResult< Expr * > ExprResult
Definition Ownership.h:249
@ Other
Other implicit parameter.
Definition Decl.h:1746
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
const ConceptSpecializationExpr * CSE
Definition SemaConcept.h:98
A normalized constraint, as defined in C++ [temp.constr.normal], is either an atomic constraint,...
Definition SemaConcept.h:36
NormalizedConstraint(const ConceptReference *ConceptId, const NamedDecl *ConstraintDecl, NormalizedConstraint *SubConstraint, const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex)
bool hasMatchingParameterMapping(ASTContext &C, const NormalizedConstraint &Other) const
NormalizedConstraint(const Expr *ConstraintExpr, const NamedDecl *ConstraintDecl, UnsignedOrNone PackIndex)
CompoundConstraintBits Compound
NormalizedConstraint(const Expr *Pattern, FoldOperatorKind OpKind, NormalizedConstraint *Constraint, const NamedDecl *ConstraintDecl)
SourceRange getSourceRange() const
NormalizedConstraint(NormalizedConstraint *LHS, CompoundConstraintKind CCK, NormalizedConstraint *RHS)
llvm::PointerUnion< const Expr *, const ConceptReference * > ExprOrConcept
Definition SemaConcept.h:54
ConstraintKind getKind() const
SourceLocation getEndLoc() const
const OccurenceList & mappingOccurenceList() const
AtomicConstraintBits Atomic
const OccurenceList & mappingOccurenceListForSubsumption() const
FoldExpandedConstraintBits FoldExpanded
TemplateParameterList * getUsedTemplateParamList() const
SourceLocation getBeginLoc() const
llvm::SmallBitVector OccurenceList
Definition SemaConcept.h:51
llvm::MutableArrayRef< TemplateArgumentLoc > getParameterMapping() const
void updateParameterMapping(OccurenceList Indexes, OccurenceList IndexesForSubsumption, llvm::MutableArrayRef< TemplateArgumentLoc > Args, TemplateParameterList *ParamList)
constexpr unsigned toInternalRepresentation() const
static constexpr UnsignedOrNone fromInternalRepresentation(unsigned Rep)