Coverage Report

Created: 2020-09-19 12:23

/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
327
  ArrayRef<TemplateArgument> getTemplateArguments() const {
95
327
    return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
96
327
                                      NumTemplateArgs);
97
327
  }
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
478
  bool isSatisfied() const {
106
478
    assert(!isValueDependent()
107
478
           && "isSatisfied called on a dependent ConceptSpecializationExpr");
108
478
    return Satisfaction->IsSatisfied;
109
478
  }
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
89
  const ASTConstraintSatisfaction &getSatisfaction() const {
115
89
    assert(!isValueDependent()
116
89
           && "getSatisfaction called on dependent ConceptSpecializationExpr");
117
89
    return *Satisfaction;
118
89
  }
119
120
1.37k
  static bool classof(const Stmt *T) {
121
1.37k
    return T->getStmtClass() == ConceptSpecializationExprClass;
122
1.37k
  }
123
124
1.75k
  SourceLocation getBeginLoc() const LLVM_READONLY {
125
1.75k
    return ConceptName.getBeginLoc();
126
1.75k
  }
127
128
540
  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
359
    return ArgsAsWritten->RAngleLoc.isValid() ? ArgsAsWritten->RAngleLoc
133
181
                                              : ConceptName.getEndLoc();
134
540
  }
135
136
  // Iterators
137
400
  child_range children() {
138
400
    return child_range(child_iterator(), child_iterator());
139
400
  }
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
398
      Satisfied(IsSatisfied) {}
175
176
2.18k
  RequirementKind getKind() const { return Kind; }
177
178
529
  bool isSatisfied() const {
179
529
    assert(!Dependent &&
180
529
           "isSatisfied can only be called on non-dependent requirements.");
181
529
    return Satisfied;
182
529
  }
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
868
  bool isDependent() const { return Dependent; }
192
193
0
  void setContainsUnexpandedParameterPack(bool Contains) {
194
0
    ContainsUnexpandedParameterPack = Contains;
195
0
  }
196
422
  bool containsUnexpandedParameterPack() const {
197
422
    return ContainsUnexpandedParameterPack;
198
422
  }
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
296
  bool isSubstitutionFailure() const {
235
296
    return Status == SS_SubstitutionFailure;
236
296
  }
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
16
    return Value.get<SubstitutionDiagnostic *>();
243
16
  }
244
245
199
  TypeSourceInfo *getType() const {
246
199
    assert(!isSubstitutionFailure() &&
247
199
           "Attempted to get type when there has been a substitution failure.");
248
199
    return Value.get<TypeSourceInfo *>();
249
199
  }
250
251
515
  static bool classof(const Requirement *R) {
252
515
    return R->getKind() == RK_Type;
253
515
  }
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
161
      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
123
      bool isDependent() const {
294
123
        return TypeConstraintInfo.getInt();
295
123
      }
296
297
117
      bool containsUnexpandedParameterPack() const {
298
117
        if (!isTypeConstraint())
299
84
          return false;
300
33
        return getTypeConstraintTemplateParameterList()
301
33
                ->containsUnexpandedParameterPack();
302
33
      }
303
304
973
      bool isEmpty() const {
305
973
        return TypeConstraintInfo.getPointer().isNull();
306
973
      }
307
308
120
      bool isSubstitutionFailure() const {
309
120
        return !isEmpty() &&
310
48
            TypeConstraintInfo.getPointer().is<SubstitutionDiagnostic *>();
311
120
      }
312
313
618
      bool isTypeConstraint() const {
314
618
        return !isEmpty() &&
315
267
            TypeConstraintInfo.getPointer().is<TemplateParameterList *>();
316
618
      }
317
318
1
      SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
319
1
        assert(isSubstitutionFailure());
320
1
        return TypeConstraintInfo.getPointer().get<SubstitutionDiagnostic *>();
321
1
      }
322
323
      const TypeConstraint *getTypeConstraint() const;
324
325
83
      TemplateParameterList *getTypeConstraintTemplateParameterList() const {
326
83
        assert(isTypeConstraint());
327
83
        return TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
328
83
      }
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
76
  bool isSimple() const { return getKind() == RK_Simple; }
365
42
  bool isCompound() const { return getKind() == RK_Compound; }
366
367
0
  bool hasNoexceptRequirement() const { return NoexceptLoc.isValid(); }
368
121
  SourceLocation getNoexceptLoc() const { return NoexceptLoc; }
369
370
29
  SatisfactionStatus getSatisfactionStatus() const { return Status; }
371
372
667
  bool isExprSubstitutionFailure() const {
373
667
    return Status == SS_ExprSubstitutionFailure;
374
667
  }
375
376
310
  const ReturnTypeRequirement &getReturnTypeRequirement() const {
377
310
    return TypeReq;
378
310
  }
379
380
  ConceptSpecializationExpr *
381
2
  getReturnTypeRequirementSubstitutedConstraintExpr() const {
382
2
    assert(Status >= SS_TypeRequirementSubstitutionFailure);
383
2
    return SubstitutedConstraintExpr;
384
2
  }
385
386
24
  SubstitutionDiagnostic *getExprSubstitutionDiagnostic() const {
387
24
    assert(isExprSubstitutionFailure() &&
388
24
           "Attempted to get expression substitution diagnostic when there has "
389
24
           "been no expression substitution failure");
390
24
    return Value.get<SubstitutionDiagnostic *>();
391
24
  }
392
393
459
  Expr *getExpr() const {
394
459
    assert(!isExprSubstitutionFailure() &&
395
459
           "ExprRequirement has no expression because there has been a "
396
459
           "substitution failure.");
397
459
    return Value.get<Expr *>();
398
459
  }
399
400
880
  static bool classof(const Requirement *R) {
401
880
    return R->getKind() == RK_Compound || 
R->getKind() == RK_Simple550
;
402
880
  }
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
86
      Satisfaction(ASTConstraintSatisfaction::Create(C, Satisfaction)) {}
436
437
313
  bool isSubstitutionFailure() const {
438
313
    return Value.is<SubstitutionDiagnostic *>();
439
313
  }
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
2
    return Value.get<SubstitutionDiagnostic *>();
446
2
  }
447
448
189
  Expr *getConstraintExpr() const {
449
189
    assert(!isSubstitutionFailure() && "getConstraintExpr() may not be called "
450
189
                                       "on nested requirements with "
451
189
                                       "substitution failures.");
452
189
    return Value.get<Expr *>();
453
189
  }
454
455
10
  const ASTConstraintSatisfaction &getConstraintSatisfaction() const {
456
10
    assert(!isSubstitutionFailure() && "getConstraintSatisfaction() may not be "
457
10
                                       "called on nested requirements with "
458
10
                                       "substitution failures.");
459
10
    return *Satisfaction;
460
10
  }
461
462
110
  static bool classof(const Requirement *R) {
463
110
    return R->getKind() == RK_Nested;
464
110
  }
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
795
  unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
487
795
    return NumLocalParameters;
488
795
  }
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
367
  ArrayRef<ParmVarDecl *> getLocalParameters() const {
513
367
    return {getTrailingObjects<ParmVarDecl *>(), NumLocalParameters};
514
367
  }
515
516
183
  RequiresExprBodyDecl *getBody() const { return Body; }
517
518
438
  ArrayRef<concepts::Requirement *> getRequirements() const {
519
438
    return {getTrailingObjects<concepts::Requirement *>(), NumRequirements};
520
438
  }
521
522
  /// \brief Whether or not the requires clause is satisfied.
523
  /// The expression must not be dependent.
524
167
  bool isSatisfied() const {
525
167
    assert(!isValueDependent()
526
167
           && "isSatisfied called on a dependent RequiresExpr");
527
167
    return RequiresExprBits.IsSatisfied;
528
167
  }
529
530
303
  SourceLocation getRequiresKWLoc() const {
531
303
    return RequiresExprBits.RequiresKWLoc;
532
303
  }
533
534
150
  SourceLocation getRBraceLoc() const { return RBraceLoc; }
535
536
422
  static bool classof(const Stmt *T) {
537
422
    return T->getStmtClass() == RequiresExprClass;
538
422
  }
539
540
729
  SourceLocation getBeginLoc() const LLVM_READONLY {
541
729
    return RequiresExprBits.RequiresKWLoc;
542
729
  }
543
133
  SourceLocation getEndLoc() const LLVM_READONLY {
544
133
    return RBraceLoc;
545
133
  }
546
547
  // Iterators
548
285
  child_range children() {
549
285
    return child_range(child_iterator(), child_iterator());
550
285
  }
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