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