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