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
33namespace clang {
34class ASTStmtReader;
35class 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.
42class ConceptSpecializationExpr final : public Expr {
43 friend class ASTReader;
44 friend class ASTStmtReader;
45
46private:
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
69public:
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
164namespace concepts {
165
166/// \brief A static requirement that can be used in a requires-expression to
167/// check properties of types and expression.
168class Requirement {
169public:
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 };
173private:
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;
182public:
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).
225class TypeRequirement : public Requirement {
226public:
227 enum SatisfactionStatus {
228 SS_Dependent,
229 SS_SubstitutionFailure,
230 SS_Satisfied
231 };
232private:
233 llvm::PointerUnion<SubstitutionDiagnostic *, TypeSourceInfo *> Value;
234 SatisfactionStatus Status;
235public:
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 cast<SubstitutionDiagnostic *>(Val: Value);
265 }
266
267 TypeSourceInfo *getType() const {
268 assert(!isSubstitutionFailure() &&
269 "Attempted to get type when there has been a substitution failure.");
270 return cast<TypeSourceInfo *>(Val: Value);
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).
280class ExprRequirement : public Requirement {
281public:
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, bool IsDependent);
314 ReturnTypeRequirement(TemplateParameterList *TPL);
315
316 bool isDependent() const {
317 return TypeConstraintInfo.getInt();
318 }
319
320 bool containsUnexpandedParameterPack() const {
321 if (!isTypeConstraint())
322 return false;
323 return getTypeConstraintTemplateParameterList()
324 ->containsUnexpandedParameterPack();
325 }
326
327 bool isEmpty() const {
328 return TypeConstraintInfo.getPointer().isNull();
329 }
330
331 bool isSubstitutionFailure() const {
332 return !isEmpty() &&
333 isa<SubstitutionDiagnostic *>(Val: TypeConstraintInfo.getPointer());
334 }
335
336 bool isTypeConstraint() const {
337 return !isEmpty() &&
338 isa<TemplateParameterList *>(Val: TypeConstraintInfo.getPointer());
339 }
340
341 SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
342 assert(isSubstitutionFailure());
343 return cast<SubstitutionDiagnostic *>(Val: TypeConstraintInfo.getPointer());
344 }
345
346 const TypeConstraint *getTypeConstraint() const;
347
348 TemplateParameterList *getTypeConstraintTemplateParameterList() const {
349 assert(isTypeConstraint());
350 return cast<TemplateParameterList *>(Val: TypeConstraintInfo.getPointer());
351 }
352 };
353private:
354 llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> Value;
355 SourceLocation NoexceptLoc; // May be empty if noexcept wasn't specified.
356 ReturnTypeRequirement TypeReq;
357 ConceptSpecializationExpr *SubstitutedConstraintExpr;
358 SatisfactionStatus Status;
359public:
360 friend ASTStmtReader;
361 friend ASTStmtWriter;
362
363 /// \brief Construct a compound requirement.
364 /// \param E the expression which is checked by this requirement.
365 /// \param IsSimple whether this was a simple requirement in source.
366 /// \param NoexceptLoc the location of the noexcept keyword, if it was
367 /// specified, otherwise an empty location.
368 /// \param Req the requirement for the type of the checked expression.
369 /// \param Status the satisfaction status of this requirement.
370 ExprRequirement(
371 Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
372 ReturnTypeRequirement Req, SatisfactionStatus Status,
373 ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr);
374
375 /// \brief Construct a compound requirement whose expression was a
376 /// substitution failure. The requirement is not satisfied.
377 /// \param E the diagnostic emitted while instantiating the original
378 /// expression.
379 /// \param IsSimple whether this was a simple requirement in source.
380 /// \param NoexceptLoc the location of the noexcept keyword, if it was
381 /// specified, otherwise an empty location.
382 /// \param Req the requirement for the type of the checked expression (omit
383 /// if no requirement was specified).
384 ExprRequirement(SubstitutionDiagnostic *E, bool IsSimple,
385 SourceLocation NoexceptLoc, ReturnTypeRequirement Req = {});
386
387 bool isSimple() const { return getKind() == RK_Simple; }
388 bool isCompound() const { return getKind() == RK_Compound; }
389
390 bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
391 SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
392
393 SatisfactionStatus getSatisfactionStatus() const { return Status; }
394
395 bool isExprSubstitutionFailure() const {
396 return Status == SS_ExprSubstitutionFailure;
397 }
398
399 const ReturnTypeRequirement &getReturnTypeRequirement() const {
400 return TypeReq;
401 }
402
403 ConceptSpecializationExpr *
404 getReturnTypeRequirementSubstitutedConstraintExpr() const {
405 assert(Status >= SS_TypeRequirementSubstitutionFailure);
406 return SubstitutedConstraintExpr;
407 }
408
409 SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
410 assert(isExprSubstitutionFailure() &&
411 "Attempted to get expression substitution diagnostic when there has "
412 "been no expression substitution failure");
413 return cast<SubstitutionDiagnostic *>(Val: Value);
414 }
415
416 Expr *getExpr() const {
417 assert(!isExprSubstitutionFailure() &&
418 "ExprRequirement has no expression because there has been a "
419 "substitution failure.");
420 return cast<Expr *>(Val: Value);
421 }
422
423 static bool classof(const Requirement *R) {
424 return R->getKind() == RK_Compound || R->getKind() == RK_Simple;
425 }
426};
427
428/// \brief A requires-expression requirement which is satisfied when a general
429/// constraint expression is satisfied ('nested' requirements).
430class NestedRequirement : public Requirement {
431 Expr *Constraint = nullptr;
432 const ASTConstraintSatisfaction *Satisfaction = nullptr;
433 bool HasInvalidConstraint = false;
434 StringRef InvalidConstraintEntity;
435
436public:
437 friend ASTStmtReader;
438 friend ASTStmtWriter;
439
440 NestedRequirement(Expr *Constraint)
441 : Requirement(RK_Nested, /*IsDependent=*/true,
442 Constraint->containsUnexpandedParameterPack()),
443 Constraint(Constraint) {
444 assert(Constraint->isInstantiationDependent() &&
445 "Nested requirement with non-dependent constraint must be "
446 "constructed with a ConstraintSatisfaction object");
447 }
448
449 NestedRequirement(ASTContext &C, Expr *Constraint,
450 const ConstraintSatisfaction &Satisfaction)
451 : Requirement(RK_Nested, Constraint->isInstantiationDependent(),
452 Constraint->containsUnexpandedParameterPack(),
453 Satisfaction.IsSatisfied),
454 Constraint(Constraint),
455 Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
456
457 NestedRequirement(StringRef InvalidConstraintEntity,
458 const ASTConstraintSatisfaction *Satisfaction)
459 : Requirement(RK_Nested,
460 /*IsDependent=*/false,
461 /*ContainsUnexpandedParameterPack*/ false,
462 Satisfaction->IsSatisfied),
463 Satisfaction(Satisfaction), HasInvalidConstraint(true),
464 InvalidConstraintEntity(InvalidConstraintEntity) {}
465
466 NestedRequirement(ASTContext &C, StringRef InvalidConstraintEntity,
467 const ConstraintSatisfaction &Satisfaction)
468 : NestedRequirement(InvalidConstraintEntity,
469 ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
470
471 bool hasInvalidConstraint() const { return HasInvalidConstraint; }
472
473 StringRef getInvalidConstraintEntity() {
474 assert(hasInvalidConstraint());
475 return InvalidConstraintEntity;
476 }
477
478 Expr *getConstraintExpr() const {
479 assert(!hasInvalidConstraint() &&
480 "getConstraintExpr() may not be called "
481 "on nested requirements with invalid constraint.");
482 return Constraint;
483 }
484
485 const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
486 return *Satisfaction;
487 }
488
489 static bool classof(const Requirement *R) {
490 return R->getKind() == RK_Nested;
491 }
492};
493} // namespace concepts
494
495/// C++2a [expr.prim.req]:
496/// A requires-expression provides a concise way to express requirements on
497/// template arguments. A requirement is one that can be checked by name
498/// lookup (6.4) or by checking properties of types and expressions.
499/// [...]
500/// A requires-expression is a prvalue of type bool [...]
501class RequiresExpr final : public Expr,
502 llvm::TrailingObjects<RequiresExpr, ParmVarDecl *,
503 concepts::Requirement *> {
504 friend TrailingObjects;
505 friend class ASTStmtReader;
506
507 unsigned NumLocalParameters;
508 unsigned NumRequirements;
509 RequiresExprBodyDecl *Body;
510 SourceLocation LParenLoc;
511 SourceLocation RParenLoc;
512 SourceLocation RBraceLoc;
513
514 unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
515 return NumLocalParameters;
516 }
517
518 RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
519 RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
520 ArrayRef<ParmVarDecl *> LocalParameters,
521 SourceLocation RParenLoc,
522 ArrayRef<concepts::Requirement *> Requirements,
523 SourceLocation RBraceLoc);
524 RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
525 unsigned NumRequirements);
526
527public:
528 static RequiresExpr *Create(ASTContext &C, SourceLocation RequiresKWLoc,
529 RequiresExprBodyDecl *Body,
530 SourceLocation LParenLoc,
531 ArrayRef<ParmVarDecl *> LocalParameters,
532 SourceLocation RParenLoc,
533 ArrayRef<concepts::Requirement *> Requirements,
534 SourceLocation RBraceLoc);
535 static RequiresExpr *
536 Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
537 unsigned NumRequirements);
538
539 ArrayRef<ParmVarDecl *> getLocalParameters() const {
540 return getTrailingObjects<ParmVarDecl *>(N: NumLocalParameters);
541 }
542
543 RequiresExprBodyDecl *getBody() const { return Body; }
544
545 ArrayRef<concepts::Requirement *> getRequirements() const {
546 return getTrailingObjects<concepts::Requirement *>(N: NumRequirements);
547 }
548
549 /// \brief Whether or not the requires clause is satisfied.
550 /// The expression must not be dependent.
551 bool isSatisfied() const {
552 assert(!isValueDependent()
553 && "isSatisfied called on a dependent RequiresExpr");
554 return RequiresExprBits.IsSatisfied;
555 }
556
557 void setSatisfied(bool IsSatisfied) {
558 assert(!isValueDependent() &&
559 "setSatisfied called on a dependent RequiresExpr");
560 RequiresExprBits.IsSatisfied = IsSatisfied;
561 }
562
563 SourceLocation getRequiresKWLoc() const {
564 return RequiresExprBits.RequiresKWLoc;
565 }
566
567 SourceLocation getLParenLoc() const { return LParenLoc; }
568 SourceLocation getRParenLoc() const { return RParenLoc; }
569 SourceLocation getRBraceLoc() const { return RBraceLoc; }
570
571 static bool classof(const Stmt *T) {
572 return T->getStmtClass() == RequiresExprClass;
573 }
574
575 SourceLocation getBeginLoc() const LLVM_READONLY {
576 return RequiresExprBits.RequiresKWLoc;
577 }
578 SourceLocation getEndLoc() const LLVM_READONLY {
579 return RBraceLoc;
580 }
581
582 // Iterators
583 child_range children() {
584 return child_range(child_iterator(), child_iterator());
585 }
586 const_child_range children() const {
587 return const_child_range(const_child_iterator(), const_child_iterator());
588 }
589};
590
591} // namespace clang
592
593#endif // LLVM_CLANG_AST_EXPRCONCEPTS_H
594

source code of clang/include/clang/AST/ExprConcepts.h