Coverage Report

Created: 2021-08-24 07:12

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