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 }
261
263 switch (getKind()) {
265 return cast<const Expr *>(Atomic.ConstraintExpr)->getEndLoc();
267 return cast<const ConceptReference *>(Atomic.ConstraintExpr)->getEndLoc();
269 return Compound.RHS->getEndLoc();
271 return FoldExpanded.Pattern->getEndLoc();
272 }
273 }
274
276
277private:
278 friend class Sema;
279 static NormalizedConstraint *
280 fromAssociatedConstraints(Sema &S, const NamedDecl *D,
282 static NormalizedConstraint *fromConstraintExpr(Sema &S, const NamedDecl *D,
283 const Expr *E,
284 UnsignedOrNone SubstIndex);
285};
286
287class CompoundConstraint : public NormalizedConstraint {
289
290public:
291 static CompoundConstraint *Create(ASTContext &Ctx, NormalizedConstraint *LHS,
293 NormalizedConstraint *RHS) {
294 return new (Ctx) CompoundConstraint(LHS, CCK, RHS);
295 }
296
298 NormalizedConstraint *LHS,
299 NormalizedConstraint *RHS) {
300 return new (Ctx) CompoundConstraint(LHS, CCK_Conjunction, RHS);
301 }
302
303 const NormalizedConstraint &getLHS() const { return *Compound.LHS; }
304
305 NormalizedConstraint &getLHS() { return *Compound.LHS; }
306
307 const NormalizedConstraint &getRHS() const { return *Compound.RHS; }
308
309 NormalizedConstraint &getRHS() { return *Compound.RHS; }
310
312 return static_cast<CompoundConstraintKind>(Compound.CCK);
313 }
314};
315
336
339 NormalizedConstraintWithParamMapping;
340
341public:
342 static AtomicConstraint *Create(ASTContext &Ctx, const Expr *ConstraintExpr,
343 const NamedDecl *ConstraintDecl,
344 UnsignedOrNone PackIndex) {
345 return new (Ctx)
346 AtomicConstraint(ConstraintExpr, ConstraintDecl, PackIndex);
347 }
348
349 const Expr *getConstraintExpr() const {
350 return cast<const Expr *>(Atomic.ConstraintExpr);
351 }
352};
353
356 NormalizedConstraintWithParamMapping;
357
358public:
359 static FoldExpandedConstraint *Create(ASTContext &Ctx, const Expr *Pattern,
360 const NamedDecl *ConstraintDecl,
361 FoldOperatorKind OpKind,
362 NormalizedConstraint *Constraint) {
363 return new (Ctx)
364 FoldExpandedConstraint(Pattern, OpKind, Constraint, ConstraintDecl);
365 }
366
368
370 return static_cast<FoldOperatorKind>(FoldExpanded.FoldOperator);
371 }
372
373 const Expr *getPattern() const { return FoldExpanded.Pattern; }
374
376 return *FoldExpanded.Constraint;
377 }
378
380 return *FoldExpanded.Constraint;
381 }
382
384 const FoldExpandedConstraint &B);
385};
386
389 NormalizedConstraintWithParamMapping;
390
391public:
392 static ConceptIdConstraint *
394 NormalizedConstraint *SubConstraint, const NamedDecl *ConstraintDecl,
395 const ConceptSpecializationExpr *CSE, UnsignedOrNone PackIndex) {
396 return new (Ctx) ConceptIdConstraint(ConceptId, ConstraintDecl,
397 SubConstraint, CSE, PackIndex);
398 }
399
403
405 return cast<const ConceptReference *>(ConceptId.ConstraintExpr);
406 }
407
409 return *ConceptId.Sub;
410 }
411
413};
414
419
420/// \brief SubsumptionChecker establishes subsumption
421/// between two set of constraints.
423public:
424 using SubsumptionCallable = llvm::function_ref<bool(
425 const AtomicConstraint &, const AtomicConstraint &)>;
426
427 SubsumptionChecker(Sema &SemaRef, SubsumptionCallable Callable = {});
428
429 std::optional<bool> Subsumes(const NamedDecl *DP,
431 const NamedDecl *DQ,
433
434 bool Subsumes(const NormalizedConstraint *P, const NormalizedConstraint *Q);
435
436private:
437 Sema &SemaRef;
439
440 // Each Literal has a unique value that is enough to establish
441 // its identity.
442 // Some constraints (fold expended) require special subsumption
443 // handling logic beyond comparing values, so we store a flag
444 // to let us quickly dispatch to each kind of variable.
445 struct Literal {
446 enum Kind { Atomic, FoldExpanded };
447
448 unsigned Value : 16;
449 LLVM_PREFERRED_TYPE(Kind)
450 unsigned Kind : 1;
451
452 bool operator==(const Literal &Other) const { return Value == Other.Value; }
453 bool operator<(const Literal &Other) const { return Value < Other.Value; }
454 };
455 using Clause = llvm::SmallVector<Literal>;
456 using Formula = llvm::SmallVector<Clause, 5>;
457
458 struct CNFFormula : Formula {
459 static constexpr auto Kind = NormalizedConstraint::CCK_Conjunction;
460 using Formula::Formula;
461 };
462 struct DNFFormula : Formula {
463 static constexpr auto Kind = NormalizedConstraint::CCK_Disjunction;
464 using Formula::Formula;
465 };
466
467 struct MappedAtomicConstraint {
468 const AtomicConstraint *Constraint;
469 Literal ID;
470 };
471
472 struct FoldExpendedConstraintKey {
474 const AtomicConstraint *Constraint;
475 Literal ID;
476 };
477
478 llvm::DenseMap<const Expr *, llvm::SmallDenseMap<llvm::FoldingSetNodeID,
479 MappedAtomicConstraint>>
480 AtomicMap;
481
482 llvm::DenseMap<const Expr *, std::vector<FoldExpendedConstraintKey>> FoldMap;
483
484 // A map from a literal to a corresponding associated constraint.
485 // We do not have enough bits left for a pointer union here :(
486 llvm::DenseMap<uint16_t, const void *> ReverseMap;
487
488 // Fold expanded constraints ask us to recursively establish subsumption.
489 // This caches the result.
490 llvm::SmallDenseMap<
491 std::pair<const FoldExpandedConstraint *, const FoldExpandedConstraint *>,
492 bool>
493 FoldSubsumptionCache;
494
495 // Each <atomic, fold expanded constraint> is represented as a single ID.
496 // This is intentionally kept small we can't handle a large number of
497 // constraints anyway.
498 uint16_t NextID;
499
500 bool Subsumes(const DNFFormula &P, const CNFFormula &Q);
501 bool Subsumes(Literal A, Literal B);
502 bool Subsumes(const FoldExpandedConstraint *A,
503 const FoldExpandedConstraint *B);
504 bool DNFSubsumes(const Clause &P, const Clause &Q);
505
506 CNFFormula CNF(const NormalizedConstraint &C);
507 DNFFormula DNF(const NormalizedConstraint &C);
508
509 template <typename FormulaType>
510 FormulaType Normalize(const NormalizedConstraint &C);
511 void AddUniqueClauseToFormula(Formula &F, Clause C);
512
513 Literal find(const AtomicConstraint *);
514 Literal find(const FoldExpandedConstraint *);
515
516 uint16_t getNewLiteralId();
517};
518
519} // namespace clang
520
521#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)