1 //===- ExprConcepts.h - C++2a Concepts expressions --------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// Defines Expressions and AST nodes for C++2a concepts.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_CLANG_AST_EXPRCONCEPTS_H
15 #define LLVM_CLANG_AST_EXPRCONCEPTS_H
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"
35 /// \brief Represents the specialization of a concept - evaluates to a prvalue
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,
43 friend class ASTStmtReader;
44 friend TrailingObjects;
46 using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
49 /// \brief The number of template arguments in the tail-allocated list of
50 /// converted template arguments.
51 unsigned NumTemplateArgs;
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
56 ASTConstraintSatisfaction *Satisfaction;
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);
66 ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
67 ArrayRef<TemplateArgument> ConvertedArgs,
68 const ConstraintSatisfaction *Satisfaction,
70 bool ContainsUnexpandedParameterPack);
72 ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
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);
84 static ConceptSpecializationExpr *
85 Create(const ASTContext &C, ConceptDecl *NamedConcept,
86 ArrayRef<TemplateArgument> ConvertedArgs,
87 const ConstraintSatisfaction *Satisfaction,
89 bool ContainsUnexpandedParameterPack);
91 static ConceptSpecializationExpr *
92 Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
94 ArrayRef<TemplateArgument> getTemplateArguments() const {
95 return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
99 /// \brief Set new template arguments for this concept specialization.
100 void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
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;
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;
120 static bool classof(const Stmt *T) {
121 return T->getStmtClass() == ConceptSpecializationExprClass;
124 SourceLocation getBeginLoc() const LLVM_READONLY {
125 return ConceptName.getBeginLoc();
128 SourceLocation getEndLoc() const LLVM_READONLY {
129 return ArgsAsWritten->RAngleLoc;
133 child_range children() {
134 return child_range(child_iterator(), child_iterator());
136 const_child_range children() const {
137 return const_child_range(const_child_iterator(), const_child_iterator());
143 /// \brief A static requirement that can be used in a requires-expression to
144 /// check properties of types and expression.
147 // Note - simple and compound requirements are both represented by the same
148 // class (ExprRequirement).
149 enum RequirementKind { RK_Type, RK_Simple, RK_Compound, RK_Nested };
151 const RequirementKind Kind;
152 // FIXME: use RequirementDependence to model dependence?
154 bool ContainsUnexpandedParameterPack : 1;
157 struct SubstitutionDiagnostic {
158 StringRef SubstitutedEntity;
159 // FIXME: Store diagnostics semantically and not as prerendered strings.
160 // Fixing this probably requires serialization of PartialDiagnostic
162 SourceLocation DiagLoc;
163 StringRef DiagMessage;
166 Requirement(RequirementKind Kind, bool IsDependent,
167 bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
168 Kind(Kind), Dependent(IsDependent),
169 ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
170 Satisfied(IsSatisfied) {}
172 RequirementKind getKind() const { return Kind; }
174 bool isSatisfied() const {
176 "isSatisfied can only be called on non-dependent requirements.");
180 void setSatisfied(bool IsSatisfied) {
182 "setSatisfied can only be called on non-dependent requirements.");
183 Satisfied = IsSatisfied;
186 void setDependent(bool IsDependent) { Dependent = IsDependent; }
187 bool isDependent() const { return Dependent; }
189 void setContainsUnexpandedParameterPack(bool Contains) {
190 ContainsUnexpandedParameterPack = Contains;
192 bool containsUnexpandedParameterPack() const {
193 return ContainsUnexpandedParameterPack;
197 /// \brief A requires-expression requirement which queries the existence of a
198 /// type name or type template specialization ('type' requirements).
199 class TypeRequirement : public Requirement {
201 enum SatisfactionStatus {
203 SS_SubstitutionFailure,
207 llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
208 SatisfactionStatus Status;
210 friend ASTStmtReader;
211 friend ASTStmtWriter;
213 /// \brief Construct a type requirement from a type. If the given type is not
214 /// dependent, this indicates that the type exists and the requirement will be
215 /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
217 TypeRequirement(TypeSourceInfo *T);
219 /// \brief Construct a type requirement when the nested name specifier is
220 /// invalid due to a bad substitution. The requirement is unsatisfied.
221 TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
222 Requirement(RK_Type, false, false, false), Value(Diagnostic),
223 Status(SS_SubstitutionFailure) {}
225 SatisfactionStatus getSatisfactionStatus() const { return Status; }
226 void setSatisfactionStatus(SatisfactionStatus Status) {
227 this->Status = Status;
230 bool isSubstitutionFailure() const {
231 return Status == SS_SubstitutionFailure;
234 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
235 assert(Status == SS_SubstitutionFailure &&
236 "Attempted to get substitution diagnostic when there has been no "
237 "substitution failure.");
238 return Value.get<SubstitutionDiagnostic *>();
241 TypeSourceInfo *getType() const {
242 assert(!isSubstitutionFailure() &&
243 "Attempted to get type when there has been a substitution failure.");
244 return Value.get<TypeSourceInfo *>();
247 static bool classof(const Requirement *R) {
248 return R->getKind() == RK_Type;
252 /// \brief A requires-expression requirement which queries the validity and
253 /// properties of an expression ('simple' and 'compound' requirements).
254 class ExprRequirement : public Requirement {
256 enum SatisfactionStatus {
258 SS_ExprSubstitutionFailure,
260 SS_TypeRequirementSubstitutionFailure,
261 SS_ConstraintsNotSatisfied,
264 class ReturnTypeRequirement {
265 llvm::PointerIntPair<
266 llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
270 friend ASTStmtReader;
271 friend ASTStmtWriter;
273 /// \brief No return type requirement was specified.
274 ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {}
276 /// \brief A return type requirement was specified but it was a
277 /// substitution failure.
278 ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
279 TypeConstraintInfo(SubstDiag, 0) {}
281 /// \brief A 'type constraint' style return type requirement.
282 /// \param TPL an invented template parameter list containing a single
283 /// type parameter with a type-constraint.
284 // TODO: Can we maybe not save the whole template parameter list and just
285 // the type constraint? Saving the whole TPL makes it easier to handle in
286 // serialization but is less elegant.
287 ReturnTypeRequirement(TemplateParameterList *TPL);
289 bool isDependent() const {
290 return TypeConstraintInfo.getInt();
293 bool containsUnexpandedParameterPack() const {
294 if (!isTypeConstraint())
296 return getTypeConstraintTemplateParameterList()
297 ->containsUnexpandedParameterPack();
300 bool isEmpty() const {
301 return TypeConstraintInfo.getPointer().isNull();
304 bool isSubstitutionFailure() const {
306 TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
309 bool isTypeConstraint() const {
311 TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
314 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
315 assert(isSubstitutionFailure());
316 return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
319 const TypeConstraint *getTypeConstraint() const;
321 TemplateParameterList *getTypeConstraintTemplateParameterList() const {
322 assert(isTypeConstraint());
323 return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
327 llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
328 SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
329 ReturnTypeRequirement TypeReq;
330 ConceptSpecializationExpr *SubstitutedConstraintExpr;
331 SatisfactionStatus Status;
333 friend ASTStmtReader;
334 friend ASTStmtWriter;
336 /// \brief Construct a compound requirement.
337 /// \param E the expression which is checked by this requirement.
338 /// \param IsSimple whether this was a simple requirement in source.
339 /// \param NoexceptLoc the location of the noexcept keyword, if it was
340 /// specified, otherwise an empty location.
341 /// \param Req the requirement for the type of the checked expression.
342 /// \param Status the satisfaction status of this requirement.
344 Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
345 ReturnTypeRequirement Req, SatisfactionStatus Status,
346 ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
348 /// \brief Construct a compound requirement whose expression was a
349 /// substitution failure. The requirement is not satisfied.
350 /// \param E the diagnostic emitted while instantiating the original
352 /// \param IsSimple whether this was a simple requirement in source.
353 /// \param NoexceptLoc the location of the noexcept keyword, if it was
354 /// specified, otherwise an empty location.
355 /// \param Req the requirement for the type of the checked expression (omit
356 /// if no requirement was specified).
357 ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
358 SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
360 bool isSimple() const { return getKind() == RK_Simple; }
361 bool isCompound() const { return getKind() == RK_Compound; }
363 bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
364 SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
366 SatisfactionStatus getSatisfactionStatus() const { return Status; }
368 bool isExprSubstitutionFailure() const {
369 return Status == SS_ExprSubstitutionFailure;
372 const ReturnTypeRequirement &getReturnTypeRequirement() const {
376 ConceptSpecializationExpr *
377 getReturnTypeRequirementSubstitutedConstraintExpr() const {
378 assert(Status >= SS_TypeRequirementSubstitutionFailure);
379 return SubstitutedConstraintExpr;
382 SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
383 assert(isExprSubstitutionFailure() &&
384 "Attempted to get expression substitution diagnostic when there has "
385 "been no expression substitution failure");
386 return Value.get<SubstitutionDiagnostic *>();
389 Expr *getExpr() const {
390 assert(!isExprSubstitutionFailure() &&
391 "ExprRequirement has no expression because there has been a "
392 "substitution failure.");
393 return Value.get<Expr *>();
396 static bool classof(const Requirement *R) {
397 return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
401 /// \brief A requires-expression requirement which is satisfied when a general
402 /// constraint expression is satisfied ('nested' requirements).
403 class NestedRequirement : public Requirement {
404 llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
405 const ASTConstraintSatisfaction *Satisfaction = nullptr;
408 friend ASTStmtReader;
409 friend ASTStmtWriter;
411 NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
412 Requirement(RK_Nested, /*Dependent=*/false,
413 /*ContainsUnexpandedParameterPack*/false,
414 /*Satisfied=*/false), Value(SubstDiag) {}
416 NestedRequirement(Expr *Constraint) :
417 Requirement(RK_Nested, /*Dependent=*/true,
418 Constraint->containsUnexpandedParameterPack()),
420 assert(Constraint->isInstantiationDependent() &&
421 "Nested requirement with non-dependent constraint must be "
422 "constructed with a ConstraintSatisfaction object");
425 NestedRequirement(ASTContext &C, Expr *Constraint,
426 const ConstraintSatisfaction &Satisfaction) :
427 Requirement(RK_Nested, Constraint->isInstantiationDependent(),
428 Constraint->containsUnexpandedParameterPack(),
429 Satisfaction.IsSatisfied),
431 Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
433 bool isSubstitutionFailure() const {
434 return Value.is<SubstitutionDiagnostic *>();
437 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
438 assert(isSubstitutionFailure() &&
439 "getSubstitutionDiagnostic() may not be called when there was no "
440 "substitution failure.");
441 return Value.get<SubstitutionDiagnostic *>();
444 Expr *getConstraintExpr() const {
445 assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
446 "on nested requirements with "
447 "substitution failures.");
448 return Value.get<Expr *>();
451 const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
452 assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
453 "called on nested requirements with "
454 "substitution failures.");
455 return *Satisfaction;
458 static bool classof(const Requirement *R) {
459 return R->getKind() == RK_Nested;
463 } // namespace concepts
465 /// C++2a [expr.prim.req]:
466 /// A requires-expression provides a concise way to express requirements on
467 /// template arguments. A requirement is one that can be checked by name
468 /// lookup (6.4) or by checking properties of types and expressions.
470 /// A requires-expression is a prvalue of type bool [...]
471 class RequiresExpr final : public Expr,
472 llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
473 concepts::Requirement *> {
474 friend TrailingObjects;
475 friend class ASTStmtReader;
477 unsigned NumLocalParameters;
478 unsigned NumRequirements;
479 RequiresExprBodyDecl *Body;
480 SourceLocation RBraceLoc;
482 unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
483 return NumLocalParameters;
486 unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
487 return NumRequirements;
490 RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
491 RequiresExprBodyDecl *Body,
492 ArrayRef<ParmVarDecl *> LocalParameters,
493 ArrayRef<concepts::Requirement *> Requirements,
494 SourceLocation RBraceLoc);
495 RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
496 unsigned NumRequirements);
499 static RequiresExpr *
500 Create(ASTContext &C, SourceLocation RequiresKWLoc,
501 RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
502 ArrayRef<concepts::Requirement *> Requirements,
503 SourceLocation RBraceLoc);
504 static RequiresExpr *
505 Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
506 unsigned NumRequirements);
508 ArrayRef<ParmVarDecl *> getLocalParameters() const {
509 return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
512 RequiresExprBodyDecl *getBody() const { return Body; }
514 ArrayRef<concepts::Requirement *> getRequirements() const {
515 return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
518 /// \brief Whether or not the requires clause is satisfied.
519 /// The expression must not be dependent.
520 bool isSatisfied() const {
521 assert(!isValueDependent()
522 && "isSatisfied called on a dependent RequiresExpr");
523 return RequiresExprBits.IsSatisfied;
526 SourceLocation getRequiresKWLoc() const {
527 return RequiresExprBits.RequiresKWLoc;
530 SourceLocation getRBraceLoc() const { return RBraceLoc; }
532 static bool classof(const Stmt *T) {
533 return T->getStmtClass() == RequiresExprClass;
536 SourceLocation getBeginLoc() const LLVM_READONLY {
537 return RequiresExprBits.RequiresKWLoc;
539 SourceLocation getEndLoc() const LLVM_READONLY {
544 child_range children() {
545 return child_range(child_iterator(), child_iterator());
547 const_child_range children() const {
548 return const_child_range(const_child_iterator(), const_child_iterator());
554 #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H