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 26 namespace clang { 27 28 class ConceptDecl; 29 class Expr; 30 class NamedDecl; 31 struct PrintingPolicy; 32 33 /// The result of a constraint satisfaction check, containing the necessary 34 /// information to diagnose an unsatisfied constraint. 35 class 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 41 public: 42 43 ConstraintSatisfaction() = default; 44 ConstraintSatisfaction(const NamedDecl * ConstraintOwner,ArrayRef<TemplateArgument> TemplateArgs)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 Profile(llvm::FoldingSetNodeID & ID,const ASTContext & C)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 HasSubstitutionFailure()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. 82 using 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. 91 struct ASTConstraintSatisfaction final : 92 llvm::TrailingObjects<ASTConstraintSatisfaction, 93 UnsatisfiedConstraintRecord> { 94 std::size_t NumRecords; 95 bool IsSatisfied : 1; 96 bool ContainsErrors : 1; 97 beginfinal98 const UnsatisfiedConstraintRecord *begin() const { 99 return getTrailingObjects<UnsatisfiedConstraintRecord>(); 100 } 101 endfinal102 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) 128 class 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 ConceptReference(NestedNameSpecifierLoc NNS,SourceLocation TemplateKWLoc,DeclarationNameInfo ConceptNameInfo,NamedDecl * FoundDecl,ConceptDecl * NamedConcept,const ASTTemplateArgumentListInfo * ArgsAsWritten)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 160 public: 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 getNestedNameSpecifierLoc()167 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { 168 return NestedNameSpec; 169 } 170 getConceptNameInfo()171 const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; } 172 getConceptNameLoc()173 SourceLocation getConceptNameLoc() const { 174 return getConceptNameInfo().getLoc(); 175 } 176 getTemplateKWLoc()177 SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } 178 getLocation()179 SourceLocation getLocation() const { return getConceptNameLoc(); } 180 getBeginLoc()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 getEndLoc()188 SourceLocation getEndLoc() const LLVM_READONLY { 189 return getTemplateArgsAsWritten() && 190 getTemplateArgsAsWritten()->getRAngleLoc().isValid() 191 ? getTemplateArgsAsWritten()->getRAngleLoc() 192 : getConceptNameInfo().getEndLoc(); 193 } 194 getSourceRange()195 SourceRange getSourceRange() const LLVM_READONLY { 196 return SourceRange(getBeginLoc(), getEndLoc()); 197 } 198 getFoundDecl()199 NamedDecl *getFoundDecl() const { 200 return FoundDecl; 201 } 202 getNamedConcept()203 ConceptDecl *getNamedConcept() const { 204 return NamedConcept; 205 } 206 getTemplateArgsAsWritten()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) hasExplicitTemplateArgs()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. 231 class TypeConstraint { 232 /// \brief The immediately-declared constraint expression introduced by this 233 /// type-constraint. 234 Expr *ImmediatelyDeclaredConstraint = nullptr; 235 ConceptReference *ConceptRef; 236 237 public: TypeConstraint(ConceptReference * ConceptRef,Expr * ImmediatelyDeclaredConstraint)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. getImmediatelyDeclaredConstraint()246 Expr *getImmediatelyDeclaredConstraint() const { 247 return ImmediatelyDeclaredConstraint; 248 } 249 getConceptReference()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. getNamedConcept()254 ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } 255 getConceptNameLoc()256 SourceLocation getConceptNameLoc() const { 257 return ConceptRef->getConceptNameLoc(); 258 } 259 hasExplicitTemplateArgs()260 bool hasExplicitTemplateArgs() const { 261 return ConceptRef->hasExplicitTemplateArgs(); 262 } 263 getTemplateArgsAsWritten()264 const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { 265 return ConceptRef->getTemplateArgsAsWritten(); 266 } 267 getTemplateKWLoc()268 SourceLocation getTemplateKWLoc() const { 269 return ConceptRef->getTemplateKWLoc(); 270 } 271 getFoundDecl()272 NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); } 273 getNestedNameSpecifierLoc()274 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { 275 return ConceptRef->getNestedNameSpecifierLoc(); 276 } 277 getConceptNameInfo()278 const DeclarationNameInfo &getConceptNameInfo() const { 279 return ConceptRef->getConceptNameInfo(); 280 } 281 print(llvm::raw_ostream & OS,const PrintingPolicy & Policy)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