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