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/Expr.h"
18 #include "clang/Basic/SourceLocation.h"
19 #include "llvm/ADT/PointerUnion.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include <utility>
22 
23 namespace clang {
24 class ConceptDecl;
25 
26 /// The result of a constraint satisfaction check, containing the necessary
27 /// information to diagnose an unsatisfied constraint.
28 class ConstraintSatisfaction : public llvm::FoldingSetNode {
29   // The template-like entity that 'owns' the constraint checked here (can be a
30   // constrained entity or a concept).
31   const NamedDecl *ConstraintOwner = nullptr;
32   llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
33 
34 public:
35 
36   ConstraintSatisfaction() = default;
37 
38   ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
39                          ArrayRef<TemplateArgument> TemplateArgs) :
40       ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
41                                                      TemplateArgs.end()) { }
42 
43   using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
44   using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
45 
46   bool IsSatisfied = false;
47   bool ContainsErrors = false;
48 
49   /// \brief Pairs of unsatisfied atomic constraint expressions along with the
50   /// substituted constraint expr, if the template arguments could be
51   /// substituted into them, or a diagnostic if substitution resulted in an
52   /// invalid expression.
53   llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details;
54 
55   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
56     Profile(ID, C, ConstraintOwner, TemplateArgs);
57   }
58 
59   static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
60                       const NamedDecl *ConstraintOwner,
61                       ArrayRef<TemplateArgument> TemplateArgs);
62 
63   bool HasSubstitutionFailure() {
64     for (const auto &Detail : Details)
65       if (Detail.second.dyn_cast<SubstitutionDiagnostic *>())
66         return true;
67     return false;
68   }
69 };
70 
71 /// Pairs of unsatisfied atomic constraint expressions along with the
72 /// substituted constraint expr, if the template arguments could be
73 /// substituted into them, or a diagnostic if substitution resulted in
74 /// an invalid expression.
75 using UnsatisfiedConstraintRecord =
76     std::pair<const Expr *,
77               llvm::PointerUnion<Expr *,
78                                  std::pair<SourceLocation, StringRef> *>>;
79 
80 /// \brief The result of a constraint satisfaction check, containing the
81 /// necessary information to diagnose an unsatisfied constraint.
82 ///
83 /// This is safe to store in an AST node, as opposed to ConstraintSatisfaction.
84 struct ASTConstraintSatisfaction final :
85     llvm::TrailingObjects<ASTConstraintSatisfaction,
86                           UnsatisfiedConstraintRecord> {
87   std::size_t NumRecords;
88   bool IsSatisfied : 1;
89   bool ContainsErrors : 1;
90 
91   const UnsatisfiedConstraintRecord *begin() const {
92     return getTrailingObjects<UnsatisfiedConstraintRecord>();
93   }
94 
95   const UnsatisfiedConstraintRecord *end() const {
96     return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords;
97   }
98 
99   ASTConstraintSatisfaction(const ASTContext &C,
100                             const ConstraintSatisfaction &Satisfaction);
101   ASTConstraintSatisfaction(const ASTContext &C,
102                             const ASTConstraintSatisfaction &Satisfaction);
103 
104   static ASTConstraintSatisfaction *
105   Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
106   static ASTConstraintSatisfaction *
107   Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction);
108 };
109 
110 /// \brief Common data class for constructs that reference concepts with
111 /// template arguments.
112 class ConceptReference {
113 protected:
114   // \brief The optional nested name specifier used when naming the concept.
115   NestedNameSpecifierLoc NestedNameSpec;
116 
117   /// \brief The location of the template keyword, if specified when naming the
118   /// concept.
119   SourceLocation TemplateKWLoc;
120 
121   /// \brief The concept name used.
122   DeclarationNameInfo ConceptName;
123 
124   /// \brief The declaration found by name lookup when the expression was
125   /// created.
126   /// Can differ from NamedConcept when, for example, the concept was found
127   /// through a UsingShadowDecl.
128   NamedDecl *FoundDecl;
129 
130   /// \brief The concept named.
131   ConceptDecl *NamedConcept;
132 
133   /// \brief The template argument list source info used to specialize the
134   /// concept.
135   const ASTTemplateArgumentListInfo *ArgsAsWritten;
136 
137 public:
138   ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
139                    DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
140                    ConceptDecl *NamedConcept,
141                    const ASTTemplateArgumentListInfo *ArgsAsWritten)
142       : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
143         ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
144         NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {}
145 
146   ConceptReference()
147       : FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {}
148 
149   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
150     return NestedNameSpec;
151   }
152 
153   const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; }
154 
155   SourceLocation getConceptNameLoc() const {
156     return getConceptNameInfo().getLoc();
157   }
158 
159   SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
160 
161   NamedDecl *getFoundDecl() const {
162     return FoundDecl;
163   }
164 
165   ConceptDecl *getNamedConcept() const {
166     return NamedConcept;
167   }
168 
169   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
170     return ArgsAsWritten;
171   }
172 
173   /// \brief Whether or not template arguments were explicitly specified in the
174   /// concept reference (they might not be in type constraints, for example)
175   bool hasExplicitTemplateArgs() const {
176     return ArgsAsWritten != nullptr;
177   }
178 };
179 
180 class TypeConstraint : public ConceptReference {
181   /// \brief The immediately-declared constraint expression introduced by this
182   /// type-constraint.
183   Expr *ImmediatelyDeclaredConstraint = nullptr;
184 
185 public:
186   TypeConstraint(NestedNameSpecifierLoc NNS,
187                  DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
188                  ConceptDecl *NamedConcept,
189                  const ASTTemplateArgumentListInfo *ArgsAsWritten,
190                  Expr *ImmediatelyDeclaredConstraint) :
191       ConceptReference(NNS, /*TemplateKWLoc=*/SourceLocation(), ConceptNameInfo,
192                        FoundDecl, NamedConcept, ArgsAsWritten),
193       ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint) {}
194 
195   /// \brief Get the immediately-declared constraint expression introduced by
196   /// this type-constraint, that is - the constraint expression that is added to
197   /// the associated constraints of the enclosing declaration in practice.
198   Expr *getImmediatelyDeclaredConstraint() const {
199     return ImmediatelyDeclaredConstraint;
200   }
201 
202   void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const;
203 };
204 
205 } // clang
206 
207 #endif // LLVM_CLANG_AST_ASTCONCEPT_H
208