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 | |