1//===--- ASTConcept.h - Concepts Related AST Data Structures ----*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file provides AST data structures related to concepts.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_AST_ASTCONCEPT_H
16#define LLVM_CLANG_AST_ASTCONCEPT_H
17#include "clang/AST/Expr.h"
18#include "clang/Basic/SourceLocation.h"
19#include "llvm/ADT/PointerUnion.h"
20#include "llvm/ADT/SmallVector.h"
21#include <string>
22#include <utility>
23namespace clang {
24class ConceptDecl;
25class ConceptSpecializationExpr;
26
27/// The result of a constraint satisfaction check, containing the necessary
28/// information to diagnose an unsatisfied constraint.
29class ConstraintSatisfaction : public llvm::FoldingSetNode {
30  // The template-like entity that 'owns' the constraint checked here (can be a
31  // constrained entity or a concept).
32  const NamedDecl *ConstraintOwner = nullptr;
33  llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
34
35public:
36
37  ConstraintSatisfaction() = default;
38
39  ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
40                         ArrayRef<TemplateArgument> TemplateArgs) :
41      ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
42                                                     TemplateArgs.end()) { }
43
44  using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
45  using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
46
47  bool IsSatisfied = false;
48
49  /// \brief Pairs of unsatisfied atomic constraint expressions along with the
50  /// substituted constraint expr, if the template arguments could be
51  /// substituted into them, or a diagnostic if substitution resulted in an
52  /// invalid expression.
53  llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details;
54
55  void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
56    Profile(ID, C, ConstraintOwner, TemplateArgs);
57  }
58
59  static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
60                      const NamedDecl *ConstraintOwner,
61                      ArrayRef<TemplateArgument> TemplateArgs);
62};
63
64/// Pairs of unsatisfied atomic constraint expressions along with the
65/// substituted constraint expr, if the template arguments could be
66/// substituted into them, or a diagnostic if substitution resulted in
67/// an invalid expression.
68using UnsatisfiedConstraintRecord =
69    std::pair<const Expr *,
70              llvm::PointerUnion<Expr *,
71                                 std::pair<SourceLocation, StringRef> *>>;
72
73/// \brief The result of a constraint satisfaction check, containing the
74/// necessary information to diagnose an unsatisfied constraint.
75///
76/// This is safe to store in an AST node, as opposed to ConstraintSatisfaction.
77struct ASTConstraintSatisfaction final :
78    llvm::TrailingObjects<ASTConstraintSatisfaction,
79                          UnsatisfiedConstraintRecord> {
80  std::size_t NumRecords;
81  bool IsSatisfied : 1;
82
83  const UnsatisfiedConstraintRecord *begin() const {
84    return getTrailingObjects<UnsatisfiedConstraintRecord>();
85  }
86
87  const UnsatisfiedConstraintRecord *end() const {
88    return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords;
89  }
90
91  ASTConstraintSatisfaction(const ASTContext &C,
92                            const ConstraintSatisfaction &Satisfaction);
93
94  static ASTConstraintSatisfaction *
95  Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
96};
97
98/// \brief Common data class for constructs that reference concepts with
99/// template arguments.
100class ConceptReference {
101protected:
102  // \brief The optional nested name specifier used when naming the concept.
103  NestedNameSpecifierLoc NestedNameSpec;
104
105  /// \brief The location of the template keyword, if specified when naming the
106  /// concept.
107  SourceLocation TemplateKWLoc;
108
109  /// \brief The concept name used.
110  DeclarationNameInfo ConceptName;
111
112  /// \brief The declaration found by name lookup when the expression was
113  /// created.
114  /// Can differ from NamedConcept when, for example, the concept was found
115  /// through a UsingShadowDecl.
116  NamedDecl *FoundDecl;
117
118  /// \brief The concept named.
119  ConceptDecl *NamedConcept;
120
121  /// \brief The template argument list source info used to specialize the
122  /// concept.
123  const ASTTemplateArgumentListInfo *ArgsAsWritten;
124
125public:
126
127  ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
128                   DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
129                   ConceptDecl *NamedConcept,
130                   const ASTTemplateArgumentListInfo *ArgsAsWritten) :
131      NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
132      ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
133      NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {}
134
135  ConceptReference() : NestedNameSpec(), TemplateKWLoc(), ConceptName(),
136      FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {}
137
138  const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
139    return NestedNameSpec;
140  }
141
142  const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; }
143
144  SourceLocation getConceptNameLoc() const {
145    return getConceptNameInfo().getLoc();
146  }
147
148  SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
149
150  NamedDecl *getFoundDecl() const {
151    return FoundDecl;
152  }
153
154  ConceptDecl *getNamedConcept() const {
155    return NamedConcept;
156  }
157
158  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
159    return ArgsAsWritten;
160  }
161
162  /// \brief Whether or not template arguments were explicitly specified in the
163  /// concept reference (they might not be in type constraints, for example)
164  bool hasExplicitTemplateArgs() const {
165    return ArgsAsWritten != nullptr;
166  }
167};
168
169class TypeConstraint : public ConceptReference {
170  /// \brief The immediately-declared constraint expression introduced by this
171  /// type-constraint.
172  Expr *ImmediatelyDeclaredConstraint = nullptr;
173
174public:
175  TypeConstraint(NestedNameSpecifierLoc NNS,
176                 DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
177                 ConceptDecl *NamedConcept,
178                 const ASTTemplateArgumentListInfo *ArgsAsWritten,
179                 Expr *ImmediatelyDeclaredConstraint) :
180      ConceptReference(NNS, /*TemplateKWLoc=*/SourceLocation(), ConceptNameInfo,
181                       FoundDecl, NamedConcept, ArgsAsWritten),
182      ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint) {}
183
184  /// \brief Get the immediately-declared constraint expression introduced by
185  /// this type-constraint, that is - the constraint expression that is added to
186  /// the associated constraints of the enclosing declaration in practice.
187  Expr *getImmediatelyDeclaredConstraint() const {
188    return ImmediatelyDeclaredConstraint;
189  }
190
191  void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const;
192};
193
194} // clang
195
196#endif // LLVM_CLANG_AST_ASTCONCEPT_H
197