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