1//===--- ASTConcept.h - Concepts Related AST Data Structures ----*- 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/// \brief This file provides AST data structures related to concepts.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_AST_ASTCONCEPT_H
15#define LLVM_CLANG_AST_ASTCONCEPT_H
16
17#include "clang/AST/DeclarationName.h"
18#include "clang/AST/NestedNameSpecifier.h"
19#include "clang/AST/TemplateBase.h"
20#include "clang/Basic/SourceLocation.h"
21#include "llvm/ADT/FoldingSet.h"
22#include "llvm/ADT/PointerUnion.h"
23#include "llvm/ADT/SmallVector.h"
24#include <utility>
25
26namespace clang {
27
28class ConceptDecl;
29class Expr;
30class NamedDecl;
31struct PrintingPolicy;
32
33/// The result of a constraint satisfaction check, containing the necessary
34/// information to diagnose an unsatisfied constraint.
35class ConstraintSatisfaction : public llvm::FoldingSetNode {
36 // The template-like entity that 'owns' the constraint checked here (can be a
37 // constrained entity or a concept).
38 const NamedDecl *ConstraintOwner = nullptr;
39 llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
40
41public:
42
43 ConstraintSatisfaction() = default;
44
45 ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
46 ArrayRef<TemplateArgument> TemplateArgs) :
47 ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
48 TemplateArgs.end()) { }
49
50 using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
51 using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
52
53 bool IsSatisfied = false;
54 bool ContainsErrors = false;
55
56 /// \brief Pairs of unsatisfied atomic constraint expressions along with the
57 /// substituted constraint expr, if the template arguments could be
58 /// substituted into them, or a diagnostic if substitution resulted in an
59 /// invalid expression.
60 llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details;
61
62 void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
63 Profile(ID, C, ConstraintOwner, TemplateArgs);
64 }
65
66 static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
67 const NamedDecl *ConstraintOwner,
68 ArrayRef<TemplateArgument> TemplateArgs);
69
70 bool HasSubstitutionFailure() {
71 for (const auto &Detail : Details)
72 if (Detail.second.dyn_cast<SubstitutionDiagnostic *>())
73 return true;
74 return false;
75 }
76};
77
78/// Pairs of unsatisfied atomic constraint expressions along with the
79/// substituted constraint expr, if the template arguments could be
80/// substituted into them, or a diagnostic if substitution resulted in
81/// an invalid expression.
82using UnsatisfiedConstraintRecord =
83 std::pair<const Expr *,
84 llvm::PointerUnion<Expr *,
85 std::pair<SourceLocation, StringRef> *>>;
86
87/// \brief The result of a constraint satisfaction check, containing the
88/// necessary information to diagnose an unsatisfied constraint.
89///
90/// This is safe to store in an AST node, as opposed to ConstraintSatisfaction.
91struct ASTConstraintSatisfaction final :
92 llvm::TrailingObjects<ASTConstraintSatisfaction,
93 UnsatisfiedConstraintRecord> {
94 std::size_t NumRecords;
95 bool IsSatisfied : 1;
96 bool ContainsErrors : 1;
97
98 const UnsatisfiedConstraintRecord *begin() const {
99 return getTrailingObjects<UnsatisfiedConstraintRecord>();
100 }
101
102 const UnsatisfiedConstraintRecord *end() const {
103 return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords;
104 }
105
106 ASTConstraintSatisfaction(const ASTContext &C,
107 const ConstraintSatisfaction &Satisfaction);
108 ASTConstraintSatisfaction(const ASTContext &C,
109 const ASTConstraintSatisfaction &Satisfaction);
110
111 static ASTConstraintSatisfaction *
112 Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
113 static ASTConstraintSatisfaction *
114 Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction);
115};
116
117/// A reference to a concept and its template args, as it appears in the code.
118///
119/// Examples:
120/// template <int X> requires is_even<X> int half = X/2;
121/// ~~~~~~~~~~ (in ConceptSpecializationExpr)
122///
123/// std::input_iterator auto I = Container.begin();
124/// ~~~~~~~~~~~~~~~~~~~ (in AutoTypeLoc)
125///
126/// template <std::derives_from<Expr> T> void dump();
127/// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl)
128class ConceptReference {
129 // \brief The optional nested name specifier used when naming the concept.
130 NestedNameSpecifierLoc NestedNameSpec;
131
132 /// \brief The location of the template keyword, if specified when naming the
133 /// concept.
134 SourceLocation TemplateKWLoc;
135
136 /// \brief The concept name used.
137 DeclarationNameInfo ConceptName;
138
139 /// \brief The declaration found by name lookup when the expression was
140 /// created.
141 /// Can differ from NamedConcept when, for example, the concept was found
142 /// through a UsingShadowDecl.
143 NamedDecl *FoundDecl;
144
145 /// \brief The concept named.
146 ConceptDecl *NamedConcept;
147
148 /// \brief The template argument list source info used to specialize the
149 /// concept.
150 const ASTTemplateArgumentListInfo *ArgsAsWritten;
151
152 ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
153 DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
154 ConceptDecl *NamedConcept,
155 const ASTTemplateArgumentListInfo *ArgsAsWritten)
156 : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
157 ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
158 NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {}
159
160public:
161 static ConceptReference *
162 Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
163 SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
164 NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
165 const ASTTemplateArgumentListInfo *ArgsAsWritten);
166
167 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
168 return NestedNameSpec;
169 }
170
171 const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; }
172
173 SourceLocation getConceptNameLoc() const {
174 return getConceptNameInfo().getLoc();
175 }
176
177 SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
178
179 SourceLocation getLocation() const { return getConceptNameLoc(); }
180
181 SourceLocation getBeginLoc() const LLVM_READONLY {
182 // Note that if the qualifier is null the template KW must also be null.
183 if (auto QualifierLoc = getNestedNameSpecifierLoc())
184 return QualifierLoc.getBeginLoc();
185 return getConceptNameInfo().getBeginLoc();
186 }
187
188 SourceLocation getEndLoc() const LLVM_READONLY {
189 return getTemplateArgsAsWritten() &&
190 getTemplateArgsAsWritten()->getRAngleLoc().isValid()
191 ? getTemplateArgsAsWritten()->getRAngleLoc()
192 : getConceptNameInfo().getEndLoc();
193 }
194
195 SourceRange getSourceRange() const LLVM_READONLY {
196 return SourceRange(getBeginLoc(), getEndLoc());
197 }
198
199 NamedDecl *getFoundDecl() const {
200 return FoundDecl;
201 }
202
203 ConceptDecl *getNamedConcept() const {
204 return NamedConcept;
205 }
206
207 const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
208 return ArgsAsWritten;
209 }
210
211 /// \brief Whether or not template arguments were explicitly specified in the
212 /// concept reference (they might not be in type constraints, for example)
213 bool hasExplicitTemplateArgs() const {
214 return ArgsAsWritten != nullptr;
215 }
216
217 void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
218 void dump() const;
219 void dump(llvm::raw_ostream &) const;
220};
221
222/// Models the abbreviated syntax to constrain a template type parameter:
223/// template <convertible_to<string> T> void print(T object);
224/// ~~~~~~~~~~~~~~~~~~~~~~
225/// Semantically, this adds an "immediately-declared constraint" with extra arg:
226/// requires convertible_to<T, string>
227///
228/// In the C++ grammar, a type-constraint is also used for auto types:
229/// convertible_to<string> auto X = ...;
230/// We do *not* model these as TypeConstraints, but AutoType(Loc) directly.
231class TypeConstraint {
232 /// \brief The immediately-declared constraint expression introduced by this
233 /// type-constraint.
234 Expr *ImmediatelyDeclaredConstraint = nullptr;
235 ConceptReference *ConceptRef;
236
237public:
238 TypeConstraint(ConceptReference *ConceptRef,
239 Expr *ImmediatelyDeclaredConstraint)
240 : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint),
241 ConceptRef(ConceptRef) {}
242
243 /// \brief Get the immediately-declared constraint expression introduced by
244 /// this type-constraint, that is - the constraint expression that is added to
245 /// the associated constraints of the enclosing declaration in practice.
246 Expr *getImmediatelyDeclaredConstraint() const {
247 return ImmediatelyDeclaredConstraint;
248 }
249
250 ConceptReference *getConceptReference() const { return ConceptRef; }
251
252 // FIXME: Instead of using these concept related functions the callers should
253 // directly work with the corresponding ConceptReference.
254 ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
255
256 SourceLocation getConceptNameLoc() const {
257 return ConceptRef->getConceptNameLoc();
258 }
259
260 bool hasExplicitTemplateArgs() const {
261 return ConceptRef->hasExplicitTemplateArgs();
262 }
263
264 const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
265 return ConceptRef->getTemplateArgsAsWritten();
266 }
267
268 SourceLocation getTemplateKWLoc() const {
269 return ConceptRef->getTemplateKWLoc();
270 }
271
272 NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); }
273
274 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
275 return ConceptRef->getNestedNameSpecifierLoc();
276 }
277
278 const DeclarationNameInfo &getConceptNameInfo() const {
279 return ConceptRef->getConceptNameInfo();
280 }
281
282 void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const {
283 ConceptRef->print(OS, Policy);
284 }
285};
286
287} // clang
288
289#endif // LLVM_CLANG_AST_ASTCONCEPT_H
290

source code of clang/include/clang/AST/ASTConcept.h