Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

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