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> |
23 | namespace clang { |
24 | class ConceptDecl; |
25 | class ConceptSpecializationExpr; |
26 | |
27 | /// The result of a constraint satisfaction check, containing the necessary |
28 | /// information to diagnose an unsatisfied constraint. |
29 | class 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 | |
35 | public: |
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. |
68 | using 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. |
77 | struct 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. |
100 | class ConceptReference { |
101 | protected: |
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 | |
125 | public: |
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 | |
169 | class TypeConstraint : public ConceptReference { |
170 | /// \brief The immediately-declared constraint expression introduced by this |
171 | /// type-constraint. |
172 | Expr *ImmediatelyDeclaredConstraint = nullptr; |
173 | |
174 | public: |
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 | |