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;
153 bool ContainsUnexpandedParameterPack : 1;
156 struct SubstitutionDiagnostic {
157 StringRef SubstitutedEntity;
158 // FIXME: Store diagnostics semantically and not as prerendered strings.
159 // Fixing this probably requires serialization of PartialDiagnostic
161 SourceLocation DiagLoc;
162 StringRef DiagMessage;
165 Requirement(RequirementKind Kind, bool IsDependent,
166 bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
167 Kind(Kind), Dependent(IsDependent),
168 ContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack),
169 Satisfied(IsSatisfied) {}
171 RequirementKind getKind() const { return Kind; }
173 bool isSatisfied() const {
175 "isSatisfied can only be called on non-dependent requirements.");
179 void setSatisfied(bool IsSatisfied) {
181 "setSatisfied can only be called on non-dependent requirements.");
182 Satisfied = IsSatisfied;
185 void setDependent(bool IsDependent) { Dependent = IsDependent; }
186 bool isDependent() const { return Dependent; }
188 void setContainsUnexpandedParameterPack(bool Contains) {
189 ContainsUnexpandedParameterPack = Contains;
191 bool containsUnexpandedParameterPack() const {
192 return ContainsUnexpandedParameterPack;
196 /// \brief A requires-expression requirement which queries the existence of a
197 /// type name or type template specialization ('type' requirements).
198 class TypeRequirement : public Requirement {
200 enum SatisfactionStatus {
202 SS_SubstitutionFailure,
206 llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
207 SatisfactionStatus Status;
209 friend ASTStmtReader;
210 friend ASTStmtWriter;
212 /// \brief Construct a type requirement from a type. If the given type is not
213 /// dependent, this indicates that the type exists and the requirement will be
214 /// satisfied. Otherwise, the SubstitutionDiagnostic constructor is to be
216 TypeRequirement(TypeSourceInfo *T);
218 /// \brief Construct a type requirement when the nested name specifier is
219 /// invalid due to a bad substitution. The requirement is unsatisfied.
220 TypeRequirement(SubstitutionDiagnostic *Diagnostic) :
221 Requirement(RK_Type, false, false, false), Value(Diagnostic),
222 Status(SS_SubstitutionFailure) {}
224 SatisfactionStatus getSatisfactionStatus() const { return Status; }
225 void setSatisfactionStatus(SatisfactionStatus Status) {
226 this->Status = Status;
229 bool isSubstitutionFailure() const {
230 return Status == SS_SubstitutionFailure;
233 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
234 assert(Status == SS_SubstitutionFailure &&
235 "Attempted to get substitution diagnostic when there has been no "
236 "substitution failure.");
237 return Value.get<SubstitutionDiagnostic *>();
240 TypeSourceInfo *getType() const {
241 assert(!isSubstitutionFailure() &&
242 "Attempted to get type when there has been a substitution failure.");
243 return Value.get<TypeSourceInfo *>();
246 static bool classof(const Requirement *R) {
247 return R->getKind() == RK_Type;
251 /// \brief A requires-expression requirement which queries the validity and
252 /// properties of an expression ('simple' and 'compound' requirements).
253 class ExprRequirement : public Requirement {
255 enum SatisfactionStatus {
257 SS_ExprSubstitutionFailure,
259 SS_TypeRequirementSubstitutionFailure,
260 SS_ConstraintsNotSatisfied,
263 class ReturnTypeRequirement {
264 llvm::PointerIntPair<
265 llvm::PointerUnion<TemplateParameterList *, SubstitutionDiagnostic *>,
269 friend ASTStmtReader;
270 friend ASTStmtWriter;
272 /// \brief No return type requirement was specified.
273 ReturnTypeRequirement() : TypeConstraintInfo(nullptr, 0) {}
275 /// \brief A return type requirement was specified but it was a
276 /// substitution failure.
277 ReturnTypeRequirement(SubstitutionDiagnostic *SubstDiag) :
278 TypeConstraintInfo(SubstDiag, 0) {}
280 /// \brief A 'type constraint' style return type requirement.
281 /// \param TPL an invented template parameter list containing a single
282 /// type parameter with a type-constraint.
283 // TODO: Can we maybe not save the whole template parameter list and just
284 // the type constraint? Saving the whole TPL makes it easier to handle in
285 // serialization but is less elegant.
286 ReturnTypeRequirement(TemplateParameterList *TPL);
288 bool isDependent() const {
289 return TypeConstraintInfo.getInt();
292 bool containsUnexpandedParameterPack() const {
293 if (!isTypeConstraint())
295 return getTypeConstraintTemplateParameterList()
296 ->containsUnexpandedParameterPack();
299 bool isEmpty() const {
300 return TypeConstraintInfo.getPointer().isNull();
303 bool isSubstitutionFailure() const {
305 TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
308 bool isTypeConstraint() const {
310 TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
313 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
314 assert(isSubstitutionFailure());
315 return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
318 const TypeConstraint *getTypeConstraint() const;
320 TemplateParameterList *getTypeConstraintTemplateParameterList() const {
321 assert(isTypeConstraint());
322 return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
326 llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
327 SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
328 ReturnTypeRequirement TypeReq;
329 ConceptSpecializationExpr *SubstitutedConstraintExpr;
330 SatisfactionStatus Status;
332 friend ASTStmtReader;
333 friend ASTStmtWriter;
335 /// \brief Construct a compound requirement.
336 /// \param E the expression which is checked by this requirement.
337 /// \param IsSimple whether this was a simple requirement in source.
338 /// \param NoexceptLoc the location of the noexcept keyword, if it was
339 /// specified, otherwise an empty location.
340 /// \param Req the requirement for the type of the checked expression.
341 /// \param Status the satisfaction status of this requirement.
343 Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
344 ReturnTypeRequirement Req, SatisfactionStatus Status,
345 ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
347 /// \brief Construct a compound requirement whose expression was a
348 /// substitution failure. The requirement is not satisfied.
349 /// \param E the diagnostic emitted while instantiating the original
351 /// \param IsSimple whether this was a simple requirement in source.
352 /// \param NoexceptLoc the location of the noexcept keyword, if it was
353 /// specified, otherwise an empty location.
354 /// \param Req the requirement for the type of the checked expression (omit
355 /// if no requirement was specified).
356 ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
357 SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
359 bool isSimple() const { return getKind() == RK_Simple; }
360 bool isCompound() const { return getKind() == RK_Compound; }
362 bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
363 SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
365 SatisfactionStatus getSatisfactionStatus() const { return Status; }
367 bool isExprSubstitutionFailure() const {
368 return Status == SS_ExprSubstitutionFailure;
371 const ReturnTypeRequirement &getReturnTypeRequirement() const {
375 ConceptSpecializationExpr *
376 getReturnTypeRequirementSubstitutedConstraintExpr() const {
377 assert(Status >= SS_TypeRequirementSubstitutionFailure);
378 return SubstitutedConstraintExpr;
381 SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
382 assert(isExprSubstitutionFailure() &&
383 "Attempted to get expression substitution diagnostic when there has "
384 "been no expression substitution failure");
385 return Value.get<SubstitutionDiagnostic *>();
388 Expr *getExpr() const {
389 assert(!isExprSubstitutionFailure() &&
390 "ExprRequirement has no expression because there has been a "
391 "substitution failure.");
392 return Value.get<Expr *>();
395 static bool classof(const Requirement *R) {
396 return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
400 /// \brief A requires-expression requirement which is satisfied when a general
401 /// constraint expression is satisfied ('nested' requirements).
402 class NestedRequirement : public Requirement {
403 llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
404 const ASTConstraintSatisfaction *Satisfaction = nullptr;
407 friend ASTStmtReader;
408 friend ASTStmtWriter;
410 NestedRequirement(SubstitutionDiagnostic *SubstDiag) :
411 Requirement(RK_Nested, /*Dependent=*/false,
412 /*ContainsUnexpandedParameterPack*/false,
413 /*Satisfied=*/false), Value(SubstDiag) {}
415 NestedRequirement(Expr *Constraint) :
416 Requirement(RK_Nested, /*Dependent=*/true,
417 Constraint->containsUnexpandedParameterPack()),
419 assert(Constraint->isInstantiationDependent() &&
420 "Nested requirement with non-dependent constraint must be "
421 "constructed with a ConstraintSatisfaction object");
424 NestedRequirement(ASTContext &C, Expr *Constraint,
425 const ConstraintSatisfaction &Satisfaction) :
426 Requirement(RK_Nested, Constraint->isInstantiationDependent(),
427 Constraint->containsUnexpandedParameterPack(),
428 Satisfaction.IsSatisfied),
430 Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
432 bool isSubstitutionFailure() const {
433 return Value.is<SubstitutionDiagnostic *>();
436 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
437 assert(isSubstitutionFailure() &&
438 "getSubstitutionDiagnostic() may not be called when there was no "
439 "substitution failure.");
440 return Value.get<SubstitutionDiagnostic *>();
443 Expr *getConstraintExpr() const {
444 assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
445 "on nested requirements with "
446 "substitution failures.");
447 return Value.get<Expr *>();
450 const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
451 assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
452 "called on nested requirements with "
453 "substitution failures.");
454 return *Satisfaction;
457 static bool classof(const Requirement *R) {
458 return R->getKind() == RK_Nested;
462 } // namespace concepts
464 /// C++2a [expr.prim.req]:
465 /// A requires-expression provides a concise way to express requirements on
466 /// template arguments. A requirement is one that can be checked by name
467 /// lookup (6.4) or by checking properties of types and expressions.
469 /// A requires-expression is a prvalue of type bool [...]
470 class RequiresExpr final : public Expr,
471 llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
472 concepts::Requirement *> {
473 friend TrailingObjects;
474 friend class ASTStmtReader;
476 unsigned NumLocalParameters;
477 unsigned NumRequirements;
478 RequiresExprBodyDecl *Body;
479 SourceLocation RBraceLoc;
481 unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
482 return NumLocalParameters;
485 unsigned numTrailingObjects(OverloadToken<concepts::Requirement *>) const {
486 return NumRequirements;
489 RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
490 RequiresExprBodyDecl *Body,
491 ArrayRef<ParmVarDecl *> LocalParameters,
492 ArrayRef<concepts::Requirement *> Requirements,
493 SourceLocation RBraceLoc);
494 RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
495 unsigned NumRequirements);
498 static RequiresExpr *
499 Create(ASTContext &C, SourceLocation RequiresKWLoc,
500 RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
501 ArrayRef<concepts::Requirement *> Requirements,
502 SourceLocation RBraceLoc);
503 static RequiresExpr *
504 Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
505 unsigned NumRequirements);
507 ArrayRef<ParmVarDecl *> getLocalParameters() const {
508 return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
511 RequiresExprBodyDecl *getBody() const { return Body; }
513 ArrayRef<concepts::Requirement *> getRequirements() const {
514 return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
517 /// \brief Whether or not the requires clause is satisfied.
518 /// The expression must not be dependent.
519 bool isSatisfied() const {
520 assert(!isValueDependent()
521 && "isSatisfied called on a dependent RequiresExpr");
522 return RequiresExprBits.IsSatisfied;
525 SourceLocation getRequiresKWLoc() const {
526 return RequiresExprBits.RequiresKWLoc;
529 SourceLocation getRBraceLoc() const { return RBraceLoc; }
531 static bool classof(const Stmt *T) {
532 return T->getStmtClass() == RequiresExprClass;
535 SourceLocation getBeginLoc() const LLVM_READONLY {
536 return RequiresExprBits.RequiresKWLoc;
538 SourceLocation getEndLoc() const LLVM_READONLY {
543 child_range children() {
544 return child_range(child_iterator(), child_iterator());
546 const_child_range children() const {
547 return const_child_range(const_child_iterator(), const_child_iterator());
553 #endif // LLVM_CLANG_AST_EXPRCONCEPTS_H