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