]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/clang/include/clang/AST/ExprConcepts.h
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[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   bool Dependent : 1;
153   bool ContainsUnexpandedParameterPack : 1;
154   bool Satisfied : 1;
155 public:
156   struct SubstitutionDiagnostic {
157     StringRef SubstitutedEntity;
158     // FIXME: Store diagnostics semantically and not as prerendered strings.
159     //  Fixing this probably requires serialization of PartialDiagnostic
160     //  objects.
161     SourceLocation DiagLoc;
162     StringRef DiagMessage;
163   };
164
165   Requirement(RequirementKind Kind, bool IsDependent,
166               bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
167       Kind(Kind), Dependent(IsDependent),
168       ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
169       Satisfied(IsSatisfied) {}
170
171   RequirementKind getKind() const { return Kind; }
172
173   bool isSatisfied() const {
174     assert(!Dependent &&
175            "isSatisfied can only be called on non-dependent requirements.");
176     return Satisfied;
177   }
178
179   void setSatisfied(bool IsSatisfied) {
180     assert(!Dependent &&
181            "setSatisfied can only be called on non-dependent requirements.");
182     Satisfied = IsSatisfied;
183   }
184
185   void setDependent(bool IsDependent) { Dependent = IsDependent; }
186   bool isDependent() const { return Dependent; }
187
188   void setContainsUnexpandedParameterPack(bool Contains) {
189     ContainsUnexpandedParameterPack = Contains;
190   }
191   bool containsUnexpandedParameterPack() const {
192     return ContainsUnexpandedParameterPack;
193   }
194 };
195
196 /// \brief A requires-expression requirement which queries the existence of a
197 /// type name or type template specialization ('type' requirements).
198 class TypeRequirement : public Requirement {
199 public:
200   enum SatisfactionStatus {
201       SS_Dependent,
202       SS_SubstitutionFailure,
203       SS_Satisfied
204   };
205 private:
206   llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
207   SatisfactionStatus Status;
208 public:
209   friend ASTStmtReader;
210   friend ASTStmtWriter;
211
212   /// \brief Construct a type requirement from a type. If the given type is not
213   /// dependent, this indicates that the type exists and the requirement will be
214   /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
215   /// used.
216   TypeRequirement(TypeSourceInfo *T);
217
218   /// \brief Construct a type requirement when the nested name specifier is
219   /// invalid due to a bad substitution. The requirement is unsatisfied.
220   TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
221       Requirement(RK_Type, false, false, false), Value(Diagnostic),
222       Status(SS_SubstitutionFailure) {}
223
224   SatisfactionStatus getSatisfactionStatus() const { return Status; }
225   void setSatisfactionStatus(SatisfactionStatus Status) {
226     this->Status = Status;
227   }
228
229   bool isSubstitutionFailure() const {
230     return Status == SS_SubstitutionFailure;
231   }
232
233   SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
234     assert(Status == SS_SubstitutionFailure &&
235            "Attempted to get substitution diagnostic when there has been no "
236            "substitution failure.");
237     return Value.get<SubstitutionDiagnostic *>();
238   }
239
240   TypeSourceInfo *getType() const {
241     assert(!isSubstitutionFailure() &&
242            "Attempted to get type when there has been a substitution failure.");
243     return Value.get<TypeSourceInfo *>();
244   }
245
246   static bool classof(const Requirement *R) {
247     return R->getKind() == RK_Type;
248   }
249 };
250
251 /// \brief A requires-expression requirement which queries the validity and
252 /// properties of an expression ('simple' and 'compound' requirements).
253 class ExprRequirement : public Requirement {
254 public:
255   enum SatisfactionStatus {
256       SS_Dependent,
257       SS_ExprSubstitutionFailure,
258       SS_NoexceptNotMet,
259       SS_TypeRequirementSubstitutionFailure,
260       SS_ConstraintsNotSatisfied,
261       SS_Satisfied
262   };
263   class ReturnTypeRequirement {
264       llvm::PointerIntPair<
265           llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
266           1, bool>
267           TypeConstraintInfo;
268   public:
269       friend ASTStmtReader;
270       friend ASTStmtWriter;
271
272       /// \brief No return type requirement was specified.
273       ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {}
274
275       /// \brief A return type requirement was specified but it was a
276       /// substitution failure.
277       ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
278           TypeConstraintInfo(SubstDiag, 0) {}
279
280       /// \brief A 'type constraint' style return type requirement.
281       /// \param TPL an invented template parameter list containing a single
282       /// type parameter with a type-constraint.
283       // TODO: Can we maybe not save the whole template parameter list and just
284       //  the type constraint? Saving the whole TPL makes it easier to handle in
285       //  serialization but is less elegant.
286       ReturnTypeRequirement(TemplateParameterList *TPL);
287
288       bool isDependent() const {
289         return TypeConstraintInfo.getInt();
290       }
291
292       bool containsUnexpandedParameterPack() const {
293         if (!isTypeConstraint())
294           return false;
295         return getTypeConstraintTemplateParameterList()
296                 ->containsUnexpandedParameterPack();
297       }
298
299       bool isEmpty() const {
300         return TypeConstraintInfo.getPointer().isNull();
301       }
302
303       bool isSubstitutionFailure() const {
304         return !isEmpty() &&
305             TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
306       }
307
308       bool isTypeConstraint() const {
309         return !isEmpty() &&
310             TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
311       }
312
313       SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
314         assert(isSubstitutionFailure());
315         return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
316       }
317
318       const TypeConstraint *getTypeConstraint() const;
319
320       TemplateParameterList *getTypeConstraintTemplateParameterList() const {
321         assert(isTypeConstraint());
322         return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
323       }
324   };
325 private:
326   llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
327   SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
328   ReturnTypeRequirement TypeReq;
329   ConceptSpecializationExpr *SubstitutedConstraintExpr;
330   SatisfactionStatus Status;
331 public:
332   friend ASTStmtReader;
333   friend ASTStmtWriter;
334
335   /// \brief Construct a compound requirement.
336   /// \param E the expression which is checked by this requirement.
337   /// \param IsSimple whether this was a simple requirement in source.
338   /// \param NoexceptLoc the location of the noexcept keyword, if it was
339   /// specified, otherwise an empty location.
340   /// \param Req the requirement for the type of the checked expression.
341   /// \param Status the satisfaction status of this requirement.
342   ExprRequirement(
343       Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
344       ReturnTypeRequirement Req, SatisfactionStatus Status,
345       ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
346
347   /// \brief Construct a compound requirement whose expression was a
348   /// substitution failure. The requirement is not satisfied.
349   /// \param E the diagnostic emitted while instantiating the original
350   /// expression.
351   /// \param IsSimple whether this was a simple requirement in source.
352   /// \param NoexceptLoc the location of the noexcept keyword, if it was
353   /// specified, otherwise an empty location.
354   /// \param Req the requirement for the type of the checked expression (omit
355   /// if no requirement was specified).
356   ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
357                   SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
358
359   bool isSimple() const { return getKind() == RK_Simple; }
360   bool isCompound() const { return getKind() == RK_Compound; }
361
362   bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
363   SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
364
365   SatisfactionStatus getSatisfactionStatus() const { return Status; }
366
367   bool isExprSubstitutionFailure() const {
368     return Status == SS_ExprSubstitutionFailure;
369   }
370
371   const ReturnTypeRequirement &getReturnTypeRequirement() const {
372     return TypeReq;
373   }
374
375   ConceptSpecializationExpr *
376   getReturnTypeRequirementSubstitutedConstraintExpr() const {
377     assert(Status >= SS_TypeRequirementSubstitutionFailure);
378     return SubstitutedConstraintExpr;
379   }
380
381   SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
382     assert(isExprSubstitutionFailure() &&
383            "Attempted to get expression substitution diagnostic when there has "
384            "been no expression substitution failure");
385     return Value.get<SubstitutionDiagnostic *>();
386   }
387
388   Expr *getExpr() const {
389     assert(!isExprSubstitutionFailure() &&
390            "ExprRequirement has no expression because there has been a "
391            "substitution failure.");
392     return Value.get<Expr *>();
393   }
394
395   static bool classof(const Requirement *R) {
396     return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
397   }
398 };
399
400 /// \brief A requires-expression requirement which is satisfied when a general
401 /// constraint expression is satisfied ('nested' requirements).
402 class NestedRequirement : public Requirement {
403   llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
404   const ASTConstraintSatisfaction *Satisfaction = nullptr;
405
406 public:
407   friend ASTStmtReader;
408   friend ASTStmtWriter;
409
410   NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
411       Requirement(RK_Nested, /*Dependent=*/false,
412                   /*ContainsUnexpandedParameterPack*/false,
413                   /*Satisfied=*/false), Value(SubstDiag) {}
414
415   NestedRequirement(Expr *Constraint) :
416       Requirement(RK_Nested, /*Dependent=*/true,
417                   Constraint->containsUnexpandedParameterPack()),
418       Value(Constraint) {
419     assert(Constraint->isInstantiationDependent() &&
420            "Nested requirement with non-dependent constraint must be "
421            "constructed with a ConstraintSatisfaction object");
422   }
423
424   NestedRequirement(ASTContext &C, Expr *Constraint,
425                     const ConstraintSatisfaction &Satisfaction) :
426       Requirement(RK_Nested, Constraint->isInstantiationDependent(),
427                   Constraint->containsUnexpandedParameterPack(),
428                   Satisfaction.IsSatisfied),
429       Value(Constraint),
430       Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
431
432   bool isSubstitutionFailure() const {
433     return Value.is<SubstitutionDiagnostic *>();
434   }
435
436   SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
437     assert(isSubstitutionFailure() &&
438            "getSubstitutionDiagnostic() may not be called when there was no "
439            "substitution failure.");
440     return Value.get<SubstitutionDiagnostic *>();
441   }
442
443   Expr *getConstraintExpr() const {
444     assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
445                                        "on nested requirements with "
446                                        "substitution failures.");
447     return Value.get<Expr *>();
448   }
449
450   const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
451     assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
452                                        "called on nested requirements with "
453                                        "substitution failures.");
454     return *Satisfaction;
455   }
456
457   static bool classof(const Requirement *R) {
458     return R->getKind() == RK_Nested;
459   }
460 };
461
462 } // namespace concepts
463
464 /// C++2a [expr.prim.req]:
465 ///     A requires-expression provides a concise way to express requirements on
466 ///     template arguments. A requirement is one that can be checked by name
467 ///     lookup (6.4) or by checking properties of types and expressions.
468 ///     [...]
469 ///     A requires-expression is a prvalue of type bool [...]
470 class RequiresExpr final : public Expr,
471     llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
472                           concepts::Requirement *> {
473   friend TrailingObjects;
474   friend class ASTStmtReader;
475
476   unsigned NumLocalParameters;
477   unsigned NumRequirements;
478   RequiresExprBodyDecl *Body;
479   SourceLocation RBraceLoc;
480
481   unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
482     return NumLocalParameters;
483   }
484
485   unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
486     return NumRequirements;
487   }
488
489   RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
490                RequiresExprBodyDecl *Body,
491                ArrayRef<ParmVarDecl *> LocalParameters,
492                ArrayRef<concepts::Requirement *> Requirements,
493                SourceLocation RBraceLoc);
494   RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
495                unsigned NumRequirements);
496
497 public:
498   static RequiresExpr *
499   Create(ASTContext &C, SourceLocation RequiresKWLoc,
500          RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
501          ArrayRef<concepts::Requirement *> Requirements,
502          SourceLocation RBraceLoc);
503   static RequiresExpr *
504   Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
505          unsigned NumRequirements);
506
507   ArrayRef<ParmVarDecl *> getLocalParameters() const {
508     return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
509   }
510
511   RequiresExprBodyDecl *getBody() const { return Body; }
512
513   ArrayRef<concepts::Requirement *> getRequirements() const {
514     return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
515   }
516
517   /// \brief Whether or not the requires clause is satisfied.
518   /// The expression must not be dependent.
519   bool isSatisfied() const {
520     assert(!isValueDependent()
521            && "isSatisfied called on a dependent RequiresExpr");
522     return RequiresExprBits.IsSatisfied;
523   }
524
525   SourceLocation getRequiresKWLoc() const {
526     return RequiresExprBits.RequiresKWLoc;
527   }
528
529   SourceLocation getRBraceLoc() const { return RBraceLoc; }
530
531   static bool classof(const Stmt *T) {
532     return T->getStmtClass() == RequiresExprClass;
533   }
534
535   SourceLocation getBeginLoc() const LLVM_READONLY {
536     return RequiresExprBits.RequiresKWLoc;
537   }
538   SourceLocation getEndLoc() const LLVM_READONLY {
539     return RBraceLoc;
540   }
541
542   // Iterators
543   child_range children() {
544     return child_range(child_iterator(), child_iterator());
545   }
546   const_child_range children() const {
547     return const_child_range(const_child_iterator(), const_child_iterator());
548   }
549 };
550
551 } // namespace clang
552
553 #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H