xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/ASTConcept.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
ConstraintSatisfaction(const NamedDecl * ConstraintOwner,ArrayRef<TemplateArgument> TemplateArgs)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 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 
Profile(llvm::FoldingSetNodeID & ID,const ASTContext & C)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 
HasSubstitutionFailure()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.
81 using 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.
88 struct ASTConstraintSatisfaction final :
89     llvm::TrailingObjects<ASTConstraintSatisfaction,
90                           UnsatisfiedConstraintRecord> {
91   std::size_t NumRecords;
92   bool IsSatisfied : 1;
93   bool ContainsErrors : 1;
94 
beginfinal95   const UnsatisfiedConstraintRecord *begin() const {
96     return getTrailingObjects<UnsatisfiedConstraintRecord>();
97   }
98 
endfinal99   const UnsatisfiedConstraintRecord *end() const {
100     return getTrailingObjects<UnsatisfiedConstraintRecord>() + 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)
125 class 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 
ConceptReference(NestedNameSpecifierLoc NNS,SourceLocation TemplateKWLoc,DeclarationNameInfo ConceptNameInfo,NamedDecl * FoundDecl,ConceptDecl * NamedConcept,const ASTTemplateArgumentListInfo * ArgsAsWritten)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 
157 public:
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 
getNestedNameSpecifierLoc()164   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
165     return NestedNameSpec;
166   }
167 
getConceptNameInfo()168   const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; }
169 
getConceptNameLoc()170   SourceLocation getConceptNameLoc() const {
171     return getConceptNameInfo().getLoc();
172   }
173 
getTemplateKWLoc()174   SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
175 
getLocation()176   SourceLocation getLocation() const { return getConceptNameLoc(); }
177 
getBeginLoc()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 
getEndLoc()185   SourceLocation getEndLoc() const LLVM_READONLY {
186     return getTemplateArgsAsWritten() &&
187                    getTemplateArgsAsWritten()->getRAngleLoc().isValid()
188                ? getTemplateArgsAsWritten()->getRAngleLoc()
189                : getConceptNameInfo().getEndLoc();
190   }
191 
getSourceRange()192   SourceRange getSourceRange() const LLVM_READONLY {
193     return SourceRange(getBeginLoc(), getEndLoc());
194   }
195 
getFoundDecl()196   NamedDecl *getFoundDecl() const {
197     return FoundDecl;
198   }
199 
getNamedConcept()200   ConceptDecl *getNamedConcept() const {
201     return NamedConcept;
202   }
203 
getTemplateArgsAsWritten()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)
hasExplicitTemplateArgs()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.
228 class TypeConstraint {
229   /// \brief The immediately-declared constraint expression introduced by this
230   /// type-constraint.
231   Expr *ImmediatelyDeclaredConstraint = nullptr;
232   ConceptReference *ConceptRef;
233 
234 public:
TypeConstraint(ConceptReference * ConceptRef,Expr * ImmediatelyDeclaredConstraint)235   TypeConstraint(ConceptReference *ConceptRef,
236                  Expr *ImmediatelyDeclaredConstraint)
237       : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint),
238         ConceptRef(ConceptRef) {}
239 
240   /// \brief Get the immediately-declared constraint expression introduced by
241   /// this type-constraint, that is - the constraint expression that is added to
242   /// the associated constraints of the enclosing declaration in practice.
getImmediatelyDeclaredConstraint()243   Expr *getImmediatelyDeclaredConstraint() const {
244     return ImmediatelyDeclaredConstraint;
245   }
246 
getConceptReference()247   ConceptReference *getConceptReference() const { return ConceptRef; }
248 
249   // FIXME: Instead of using these concept related functions the callers should
250   // directly work with the corresponding ConceptReference.
getNamedConcept()251   ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
252 
getConceptNameLoc()253   SourceLocation getConceptNameLoc() const {
254     return ConceptRef->getConceptNameLoc();
255   }
256 
hasExplicitTemplateArgs()257   bool hasExplicitTemplateArgs() const {
258     return ConceptRef->hasExplicitTemplateArgs();
259   }
260 
getTemplateArgsAsWritten()261   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
262     return ConceptRef->getTemplateArgsAsWritten();
263   }
264 
getTemplateKWLoc()265   SourceLocation getTemplateKWLoc() const {
266     return ConceptRef->getTemplateKWLoc();
267   }
268 
getFoundDecl()269   NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); }
270 
getNestedNameSpecifierLoc()271   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
272     return ConceptRef->getNestedNameSpecifierLoc();
273   }
274 
getConceptNameInfo()275   const DeclarationNameInfo &getConceptNameInfo() const {
276     return ConceptRef->getConceptNameInfo();
277   }
278 
print(llvm::raw_ostream & OS,const PrintingPolicy & Policy)279   void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const {
280     ConceptRef->print(OS, Policy);
281   }
282 };
283 
284 } // clang
285 
286 #endif // LLVM_CLANG_AST_ASTCONCEPT_H
287