Coverage Report

Created: 2020-02-25 14:32

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