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