]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/include/clang/AST/ExprConcepts.h
Add 'sys/contrib/device-tree/' from commit '5ee353c36d3c9c7f63df7c7671875e73fba70958'
[FreeBSD/FreeBSD.git] / contrib / llvm-project / clang / include / clang / AST / ExprConcepts.h
1 //===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
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 /// \file
10 /// Defines Expressions and AST nodes for C++2a concepts.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
15 #define LLVM_CLANG_AST_EXPRCONCEPTS_H
16
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/ASTConcept.h"
19 #include "clang/AST/Decl.h"
20 #include "clang/AST/DeclarationName.h"
21 #include "clang/AST/DeclTemplate.h"
22 #include "clang/AST/Expr.h"
23 #include "clang/AST/NestedNameSpecifier.h"
24 #include "clang/AST/TemplateBase.h"
25 #include "clang/AST/Type.h"
26 #include "clang/Basic/SourceLocation.h"
27 #include "llvm/Support/TrailingObjects.h"
28 #include <utility>
29 #include <string>
30
31 namespace clang {
32 class ASTStmtReader;
33 class ASTStmtWriter;
34
35 /// \brief Represents the specialization of a concept - evaluates to a prvalue
36 /// of type bool.
37 ///
38 /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
39 /// specialization of a concept results in a prvalue of type bool.
40 class ConceptSpecializationExpr final : public Expr, public ConceptReference,
41       private llvm::TrailingObjects<ConceptSpecializationExpr,
42                                     TemplateArgument> {
43   friend class ASTStmtReader;
44   friend TrailingObjects;
45 public:
46   using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
47
48 protected:
49   /// \brief The number of template arguments in the tail-allocated list of
50   /// converted template arguments.
51   unsigned NumTemplateArgs;
52
53   /// \brief Information about the satisfaction of the named concept with the
54   /// given arguments. If this expression is value dependent, this is to be
55   /// ignored.
56   ASTConstraintSatisfaction *Satisfaction;
57
58   ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
59                             SourceLocation TemplateKWLoc,
60                             DeclarationNameInfo ConceptNameInfo,
61                             NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
62                             const ASTTemplateArgumentListInfo *ArgsAsWritten,
63                             ArrayRef<TemplateArgument> ConvertedArgs,
64                             const ConstraintSatisfaction *Satisfaction);
65
66   ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
67                             ArrayRef<TemplateArgument> ConvertedArgs,
68                             const ConstraintSatisfaction *Satisfaction,
69                             bool Dependent,
70                             bool ContainsUnexpandedParameterPack);
71
72   ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
73
74 public:
75
76   static ConceptSpecializationExpr *
77   Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
78          SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
79          NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
80          const ASTTemplateArgumentListInfo *ArgsAsWritten,
81          ArrayRef<TemplateArgument> ConvertedArgs,
82          const ConstraintSatisfaction *Satisfaction);
83
84   static ConceptSpecializationExpr *
85   Create(const ASTContext &C, ConceptDecl *NamedConcept,
86          ArrayRef<TemplateArgument> ConvertedArgs,
87          const ConstraintSatisfaction *Satisfaction,
88          bool Dependent,
89          bool ContainsUnexpandedParameterPack);
90
91   static ConceptSpecializationExpr *
92   Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
93
94   ArrayRef<TemplateArgument> getTemplateArguments() const {
95     return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
96                                       NumTemplateArgs);
97   }
98
99   /// \brief Set new template arguments for this concept specialization.
100   void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
101
102   /// \brief Whether or not the concept with the given arguments was satisfied
103   /// when the expression was created.
104   /// The expression must not be dependent.
105   bool isSatisfied() const {
106     assert(!isValueDependent()
107            && "isSatisfied called on a dependent ConceptSpecializationExpr");
108     return Satisfaction->IsSatisfied;
109   }
110
111   /// \brief Get elaborated satisfaction info about the template arguments'
112   /// satisfaction of the named concept.
113   /// The expression must not be dependent.
114   const ASTConstraintSatisfaction &getSatisfaction() const {
115     assert(!isValueDependent()
116            && "getSatisfaction called on dependent ConceptSpecializationExpr");
117     return *Satisfaction;
118   }
119
120   static bool classof(const Stmt *T) {
121     return T->getStmtClass() == ConceptSpecializationExprClass;
122   }
123
124   SourceLocation getBeginLoc() const LLVM_READONLY {
125     return ConceptName.getBeginLoc();
126   }
127
128   SourceLocation getEndLoc() const LLVM_READONLY {
129     return ArgsAsWritten->RAngleLoc;
130   }
131
132   // Iterators
133   child_range children() {
134     return child_range(child_iterator(), child_iterator());
135   }
136   const_child_range children() const {
137     return const_child_range(const_child_iterator(), const_child_iterator());
138   }
139 };
140
141 namespace concepts {
142
143 /// \brief A static requirement that can be used in a requires-expression to
144 /// check properties of types and expression.
145 class Requirement {
146 public:
147   // Note - simple and compound requirements are both represented by the same
148   // class (ExprRequirement).
149   enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
150 private:
151   const RequirementKind Kind;
152   // FIXME: use RequirementDependence to model dependence?
153   bool Dependent : 1;
154   bool ContainsUnexpandedParameterPack : 1;
155   bool Satisfied : 1;
156 public:
157   struct SubstitutionDiagnostic {
158     StringRef SubstitutedEntity;
159     // FIXME: Store diagnostics semantically and not as prerendered strings.
160     //  Fixing this probably requires serialization of PartialDiagnostic
161     //  objects.
162     SourceLocation DiagLoc;
163     StringRef DiagMessage;
164   };
165
166   Requirement(RequirementKind Kind, bool IsDependent,
167               bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
168       Kind(Kind), Dependent(IsDependent),
169       ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
170       Satisfied(IsSatisfied) {}
171
172   RequirementKind getKind() const { return Kind; }
173
174   bool isSatisfied() const {
175     assert(!Dependent &&
176            "isSatisfied can only be called on non-dependent requirements.");
177     return Satisfied;
178   }
179
180   void setSatisfied(bool IsSatisfied) {
181     assert(!Dependent &&
182            "setSatisfied can only be called on non-dependent requirements.");
183     Satisfied = IsSatisfied;
184   }
185
186   void setDependent(bool IsDependent) { Dependent = IsDependent; }
187   bool isDependent() const { return Dependent; }
188
189   void setContainsUnexpandedParameterPack(bool Contains) {
190     ContainsUnexpandedParameterPack = Contains;
191   }
192   bool containsUnexpandedParameterPack() const {
193     return ContainsUnexpandedParameterPack;
194   }
195 };
196
197 /// \brief A requires-expression requirement which queries the existence of a
198 /// type name or type template specialization ('type' requirements).
199 class TypeRequirement : public Requirement {
200 public:
201   enum SatisfactionStatus {
202       SS_Dependent,
203       SS_SubstitutionFailure,
204       SS_Satisfied
205   };
206 private:
207   llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
208   SatisfactionStatus Status;
209 public:
210   friend ASTStmtReader;
211   friend ASTStmtWriter;
212
213   /// \brief Construct a type requirement from a type. If the given type is not
214   /// dependent, this indicates that the type exists and the requirement will be
215   /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
216   /// used.
217   TypeRequirement(TypeSourceInfo *T);
218
219   /// \brief Construct a type requirement when the nested name specifier is
220   /// invalid due to a bad substitution. The requirement is unsatisfied.
221   TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
222       Requirement(RK_Type, false, false, false), Value(Diagnostic),
223       Status(SS_SubstitutionFailure) {}
224
225   SatisfactionStatus getSatisfactionStatus() const { return Status; }
226   void setSatisfactionStatus(SatisfactionStatus Status) {
227     this->Status = Status;
228   }
229
230   bool isSubstitutionFailure() const {
231     return Status == SS_SubstitutionFailure;
232   }
233
234   SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
235     assert(Status == SS_SubstitutionFailure &&
236            "Attempted to get substitution diagnostic when there has been no "
237            "substitution failure.");
238     return Value.get<SubstitutionDiagnostic *>();
239   }
240
241   TypeSourceInfo *getType() const {
242     assert(!isSubstitutionFailure() &&
243            "Attempted to get type when there has been a substitution failure.");
244     return Value.get<TypeSourceInfo *>();
245   }
246
247   static bool classof(const Requirement *R) {
248     return R->getKind() == RK_Type;
249   }
250 };
251
252 /// \brief A requires-expression requirement which queries the validity and
253 /// properties of an expression ('simple' and 'compound' requirements).
254 class ExprRequirement : public Requirement {
255 public:
256   enum SatisfactionStatus {
257       SS_Dependent,
258       SS_ExprSubstitutionFailure,
259       SS_NoexceptNotMet,
260       SS_TypeRequirementSubstitutionFailure,
261       SS_ConstraintsNotSatisfied,
262       SS_Satisfied
263   };
264   class ReturnTypeRequirement {
265       llvm::PointerIntPair<
266           llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
267           1, bool>
268           TypeConstraintInfo;
269   public:
270       friend ASTStmtReader;
271       friend ASTStmtWriter;
272
273       /// \brief No return type requirement was specified.
274       ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {}
275
276       /// \brief A return type requirement was specified but it was a
277       /// substitution failure.
278       ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
279           TypeConstraintInfo(SubstDiag, 0) {}
280
281       /// \brief A 'type constraint' style return type requirement.
282       /// \param TPL an invented template parameter list containing a single
283       /// type parameter with a type-constraint.
284       // TODO: Can we maybe not save the whole template parameter list and just
285       //  the type constraint? Saving the whole TPL makes it easier to handle in
286       //  serialization but is less elegant.
287       ReturnTypeRequirement(TemplateParameterList *TPL);
288
289       bool isDependent() const {
290         return TypeConstraintInfo.getInt();
291       }
292
293       bool containsUnexpandedParameterPack() const {
294         if (!isTypeConstraint())
295           return false;
296         return getTypeConstraintTemplateParameterList()
297                 ->containsUnexpandedParameterPack();
298       }
299
300       bool isEmpty() const {
301         return TypeConstraintInfo.getPointer().isNull();
302       }
303
304       bool isSubstitutionFailure() const {
305         return !isEmpty() &&
306             TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
307       }
308
309       bool isTypeConstraint() const {
310         return !isEmpty() &&
311             TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
312       }
313
314       SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
315         assert(isSubstitutionFailure());
316         return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
317       }
318
319       const TypeConstraint *getTypeConstraint() const;
320
321       TemplateParameterList *getTypeConstraintTemplateParameterList() const {
322         assert(isTypeConstraint());
323         return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
324       }
325   };
326 private:
327   llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
328   SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
329   ReturnTypeRequirement TypeReq;
330   ConceptSpecializationExpr *SubstitutedConstraintExpr;
331   SatisfactionStatus Status;
332 public:
333   friend ASTStmtReader;
334   friend ASTStmtWriter;
335
336   /// \brief Construct a compound requirement.
337   /// \param E the expression which is checked by this requirement.
338   /// \param IsSimple whether this was a simple requirement in source.
339   /// \param NoexceptLoc the location of the noexcept keyword, if it was
340   /// specified, otherwise an empty location.
341   /// \param Req the requirement for the type of the checked expression.
342   /// \param Status the satisfaction status of this requirement.
343   ExprRequirement(
344       Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
345       ReturnTypeRequirement Req, SatisfactionStatus Status,
346       ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
347
348   /// \brief Construct a compound requirement whose expression was a
349   /// substitution failure. The requirement is not satisfied.
350   /// \param E the diagnostic emitted while instantiating the original
351   /// expression.
352   /// \param IsSimple whether this was a simple requirement in source.
353   /// \param NoexceptLoc the location of the noexcept keyword, if it was
354   /// specified, otherwise an empty location.
355   /// \param Req the requirement for the type of the checked expression (omit
356   /// if no requirement was specified).
357   ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
358                   SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
359
360   bool isSimple() const { return getKind() == RK_Simple; }
361   bool isCompound() const { return getKind() == RK_Compound; }
362
363   bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
364   SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
365
366   SatisfactionStatus getSatisfactionStatus() const { return Status; }
367
368   bool isExprSubstitutionFailure() const {
369     return Status == SS_ExprSubstitutionFailure;
370   }
371
372   const ReturnTypeRequirement &getReturnTypeRequirement() const {
373     return TypeReq;
374   }
375
376   ConceptSpecializationExpr *
377   getReturnTypeRequirementSubstitutedConstraintExpr() const {
378     assert(Status >= SS_TypeRequirementSubstitutionFailure);
379     return SubstitutedConstraintExpr;
380   }
381
382   SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
383     assert(isExprSubstitutionFailure() &&
384            "Attempted to get expression substitution diagnostic when there has "
385            "been no expression substitution failure");
386     return Value.get<SubstitutionDiagnostic *>();
387   }
388
389   Expr *getExpr() const {
390     assert(!isExprSubstitutionFailure() &&
391            "ExprRequirement has no expression because there has been a "
392            "substitution failure.");
393     return Value.get<Expr *>();
394   }
395
396   static bool classof(const Requirement *R) {
397     return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
398   }
399 };
400
401 /// \brief A requires-expression requirement which is satisfied when a general
402 /// constraint expression is satisfied ('nested' requirements).
403 class NestedRequirement : public Requirement {
404   llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
405   const ASTConstraintSatisfaction *Satisfaction = nullptr;
406
407 public:
408   friend ASTStmtReader;
409   friend ASTStmtWriter;
410
411   NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
412       Requirement(RK_Nested, /*Dependent=*/false,
413                   /*ContainsUnexpandedParameterPack*/false,
414                   /*Satisfied=*/false), Value(SubstDiag) {}
415
416   NestedRequirement(Expr *Constraint) :
417       Requirement(RK_Nested, /*Dependent=*/true,
418                   Constraint->containsUnexpandedParameterPack()),
419       Value(Constraint) {
420     assert(Constraint->isInstantiationDependent() &&
421            "Nested requirement with non-dependent constraint must be "
422            "constructed with a ConstraintSatisfaction object");
423   }
424
425   NestedRequirement(ASTContext &C, Expr *Constraint,
426                     const ConstraintSatisfaction &Satisfaction) :
427       Requirement(RK_Nested, Constraint->isInstantiationDependent(),
428                   Constraint->containsUnexpandedParameterPack(),
429                   Satisfaction.IsSatisfied),
430       Value(Constraint),
431       Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
432
433   bool isSubstitutionFailure() const {
434     return Value.is<SubstitutionDiagnostic *>();
435   }
436
437   SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
438     assert(isSubstitutionFailure() &&
439            "getSubstitutionDiagnostic() may not be called when there was no "
440            "substitution failure.");
441     return Value.get<SubstitutionDiagnostic *>();
442   }
443
444   Expr *getConstraintExpr() const {
445     assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
446                                        "on nested requirements with "
447                                        "substitution failures.");
448     return Value.get<Expr *>();
449   }
450
451   const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
452     assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
453                                        "called on nested requirements with "
454                                        "substitution failures.");
455     return *Satisfaction;
456   }
457
458   static bool classof(const Requirement *R) {
459     return R->getKind() == RK_Nested;
460   }
461 };
462
463 } // namespace concepts
464
465 /// C++2a [expr.prim.req]:
466 ///     A requires-expression provides a concise way to express requirements on
467 ///     template arguments. A requirement is one that can be checked by name
468 ///     lookup (6.4) or by checking properties of types and expressions.
469 ///     [...]
470 ///     A requires-expression is a prvalue of type bool [...]
471 class RequiresExpr final : public Expr,
472     llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
473                           concepts::Requirement *> {
474   friend TrailingObjects;
475   friend class ASTStmtReader;
476
477   unsigned NumLocalParameters;
478   unsigned NumRequirements;
479   RequiresExprBodyDecl *Body;
480   SourceLocation RBraceLoc;
481
482   unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
483     return NumLocalParameters;
484   }
485
486   unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
487     return NumRequirements;
488   }
489
490   RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
491                RequiresExprBodyDecl *Body,
492                ArrayRef<ParmVarDecl *> LocalParameters,
493                ArrayRef<concepts::Requirement *> Requirements,
494                SourceLocation RBraceLoc);
495   RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
496                unsigned NumRequirements);
497
498 public:
499   static RequiresExpr *
500   Create(ASTContext &C, SourceLocation RequiresKWLoc,
501          RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
502          ArrayRef<concepts::Requirement *> Requirements,
503          SourceLocation RBraceLoc);
504   static RequiresExpr *
505   Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
506          unsigned NumRequirements);
507
508   ArrayRef<ParmVarDecl *> getLocalParameters() const {
509     return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
510   }
511
512   RequiresExprBodyDecl *getBody() const { return Body; }
513
514   ArrayRef<concepts::Requirement *> getRequirements() const {
515     return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
516   }
517
518   /// \brief Whether or not the requires clause is satisfied.
519   /// The expression must not be dependent.
520   bool isSatisfied() const {
521     assert(!isValueDependent()
522            && "isSatisfied called on a dependent RequiresExpr");
523     return RequiresExprBits.IsSatisfied;
524   }
525
526   SourceLocation getRequiresKWLoc() const {
527     return RequiresExprBits.RequiresKWLoc;
528   }
529
530   SourceLocation getRBraceLoc() const { return RBraceLoc; }
531
532   static bool classof(const Stmt *T) {
533     return T->getStmtClass() == RequiresExprClass;
534   }
535
536   SourceLocation getBeginLoc() const LLVM_READONLY {
537     return RequiresExprBits.RequiresKWLoc;
538   }
539   SourceLocation getEndLoc() const LLVM_READONLY {
540     return RBraceLoc;
541   }
542
543   // Iterators
544   child_range children() {
545     return child_range(child_iterator(), child_iterator());
546   }
547   const_child_range children() const {
548     return const_child_range(const_child_iterator(), const_child_iterator());
549   }
550 };
551
552 } // namespace clang
553
554 #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H