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