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