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