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