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 "clang/Basic/UnsignedOrNone.h" 22 #include "llvm/ADT/FoldingSet.h" 23 #include "llvm/ADT/PointerUnion.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include <utility> 26 27 namespace clang { 28 29 class ConceptDecl; 30 class Expr; 31 class NamedDecl; 32 struct PrintingPolicy; 33 34 /// The result of a constraint satisfaction check, containing the necessary 35 /// information to diagnose an unsatisfied constraint. 36 class ConstraintSatisfaction : public llvm::FoldingSetNode { 37 // The template-like entity that 'owns' the constraint checked here (can be a 38 // constrained entity or a concept). 39 const NamedDecl *ConstraintOwner = nullptr; 40 llvm::SmallVector<TemplateArgument, 4> TemplateArgs; 41 42 public: 43 44 ConstraintSatisfaction() = default; 45 ConstraintSatisfaction(const NamedDecl * ConstraintOwner,ArrayRef<TemplateArgument> TemplateArgs)46 ConstraintSatisfaction(const NamedDecl *ConstraintOwner, 47 ArrayRef<TemplateArgument> TemplateArgs) 48 : ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {} 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 The substituted constraint expr, if the template arguments could be 57 /// substituted into them, or a diagnostic if substitution resulted in an 58 /// invalid expression. 59 llvm::SmallVector<Detail, 4> Details; 60 Profile(llvm::FoldingSetNodeID & ID,const ASTContext & C)61 void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) { 62 Profile(ID, C, ConstraintOwner, TemplateArgs); 63 } 64 65 static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C, 66 const NamedDecl *ConstraintOwner, 67 ArrayRef<TemplateArgument> TemplateArgs); 68 HasSubstitutionFailure()69 bool HasSubstitutionFailure() { 70 for (const auto &Detail : Details) 71 if (Detail.dyn_cast<SubstitutionDiagnostic *>()) 72 return true; 73 return false; 74 } 75 }; 76 77 /// Pairs of unsatisfied atomic constraint expressions along with the 78 /// substituted constraint expr, if the template arguments could be 79 /// substituted into them, or a diagnostic if substitution resulted in 80 /// an invalid expression. 81 using UnsatisfiedConstraintRecord = 82 llvm::PointerUnion<Expr *, std::pair<SourceLocation, StringRef> *>; 83 84 /// \brief The result of a constraint satisfaction check, containing the 85 /// necessary information to diagnose an unsatisfied constraint. 86 /// 87 /// This is safe to store in an AST node, as opposed to ConstraintSatisfaction. 88 struct ASTConstraintSatisfaction final : 89 llvm::TrailingObjects<ASTConstraintSatisfaction, 90 UnsatisfiedConstraintRecord> { 91 std::size_t NumRecords; 92 bool IsSatisfied : 1; 93 bool ContainsErrors : 1; 94 beginfinal95 const UnsatisfiedConstraintRecord *begin() const { 96 return getTrailingObjects(); 97 } 98 endfinal99 const UnsatisfiedConstraintRecord *end() const { 100 return getTrailingObjects() + NumRecords; 101 } 102 103 ASTConstraintSatisfaction(const ASTContext &C, 104 const ConstraintSatisfaction &Satisfaction); 105 ASTConstraintSatisfaction(const ASTContext &C, 106 const ASTConstraintSatisfaction &Satisfaction); 107 108 static ASTConstraintSatisfaction * 109 Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction); 110 static ASTConstraintSatisfaction * 111 Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction); 112 }; 113 114 /// A reference to a concept and its template args, as it appears in the code. 115 /// 116 /// Examples: 117 /// template <int X> requires is_even<X> int half = X/2; 118 /// ~~~~~~~~~~ (in ConceptSpecializationExpr) 119 /// 120 /// std::input_iterator auto I = Container.begin(); 121 /// ~~~~~~~~~~~~~~~~~~~ (in AutoTypeLoc) 122 /// 123 /// template <std::derives_from<Expr> T> void dump(); 124 /// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl) 125 class ConceptReference { 126 // \brief The optional nested name specifier used when naming the concept. 127 NestedNameSpecifierLoc NestedNameSpec; 128 129 /// \brief The location of the template keyword, if specified when naming the 130 /// concept. 131 SourceLocation TemplateKWLoc; 132 133 /// \brief The concept name used. 134 DeclarationNameInfo ConceptName; 135 136 /// \brief The declaration found by name lookup when the expression was 137 /// created. 138 /// Can differ from NamedConcept when, for example, the concept was found 139 /// through a UsingShadowDecl. 140 NamedDecl *FoundDecl; 141 142 /// \brief The concept named. 143 ConceptDecl *NamedConcept; 144 145 /// \brief The template argument list source info used to specialize the 146 /// concept. 147 const ASTTemplateArgumentListInfo *ArgsAsWritten; 148 ConceptReference(NestedNameSpecifierLoc NNS,SourceLocation TemplateKWLoc,DeclarationNameInfo ConceptNameInfo,NamedDecl * FoundDecl,ConceptDecl * NamedConcept,const ASTTemplateArgumentListInfo * ArgsAsWritten)149 ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, 150 DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, 151 ConceptDecl *NamedConcept, 152 const ASTTemplateArgumentListInfo *ArgsAsWritten) 153 : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), 154 ConceptName(ConceptNameInfo), FoundDecl(FoundDecl), 155 NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {} 156 157 public: 158 static ConceptReference * 159 Create(const ASTContext &C, NestedNameSpecifierLoc NNS, 160 SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, 161 NamedDecl *FoundDecl, ConceptDecl *NamedConcept, 162 const ASTTemplateArgumentListInfo *ArgsAsWritten); 163 getNestedNameSpecifierLoc()164 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { 165 return NestedNameSpec; 166 } 167 getConceptNameInfo()168 const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; } 169 getConceptNameLoc()170 SourceLocation getConceptNameLoc() const { 171 return getConceptNameInfo().getLoc(); 172 } 173 getTemplateKWLoc()174 SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } 175 getLocation()176 SourceLocation getLocation() const { return getConceptNameLoc(); } 177 getBeginLoc()178 SourceLocation getBeginLoc() const LLVM_READONLY { 179 // Note that if the qualifier is null the template KW must also be null. 180 if (auto QualifierLoc = getNestedNameSpecifierLoc()) 181 return QualifierLoc.getBeginLoc(); 182 return getConceptNameInfo().getBeginLoc(); 183 } 184 getEndLoc()185 SourceLocation getEndLoc() const LLVM_READONLY { 186 return getTemplateArgsAsWritten() && 187 getTemplateArgsAsWritten()->getRAngleLoc().isValid() 188 ? getTemplateArgsAsWritten()->getRAngleLoc() 189 : getConceptNameInfo().getEndLoc(); 190 } 191 getSourceRange()192 SourceRange getSourceRange() const LLVM_READONLY { 193 return SourceRange(getBeginLoc(), getEndLoc()); 194 } 195 getFoundDecl()196 NamedDecl *getFoundDecl() const { 197 return FoundDecl; 198 } 199 getNamedConcept()200 ConceptDecl *getNamedConcept() const { 201 return NamedConcept; 202 } 203 getTemplateArgsAsWritten()204 const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { 205 return ArgsAsWritten; 206 } 207 208 /// \brief Whether or not template arguments were explicitly specified in the 209 /// concept reference (they might not be in type constraints, for example) hasExplicitTemplateArgs()210 bool hasExplicitTemplateArgs() const { 211 return ArgsAsWritten != nullptr; 212 } 213 214 void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; 215 void dump() const; 216 void dump(llvm::raw_ostream &) const; 217 }; 218 219 /// Models the abbreviated syntax to constrain a template type parameter: 220 /// template <convertible_to<string> T> void print(T object); 221 /// ~~~~~~~~~~~~~~~~~~~~~~ 222 /// Semantically, this adds an "immediately-declared constraint" with extra arg: 223 /// requires convertible_to<T, string> 224 /// 225 /// In the C++ grammar, a type-constraint is also used for auto types: 226 /// convertible_to<string> auto X = ...; 227 /// We do *not* model these as TypeConstraints, but AutoType(Loc) directly. 228 class TypeConstraint { 229 /// \brief The immediately-declared constraint expression introduced by this 230 /// type-constraint. 231 Expr *ImmediatelyDeclaredConstraint = nullptr; 232 ConceptReference *ConceptRef; 233 UnsignedOrNone ArgPackSubstIndex; 234 235 public: TypeConstraint(ConceptReference * ConceptRef,Expr * ImmediatelyDeclaredConstraint,UnsignedOrNone ArgPackSubstIndex)236 TypeConstraint(ConceptReference *ConceptRef, 237 Expr *ImmediatelyDeclaredConstraint, 238 UnsignedOrNone ArgPackSubstIndex) 239 : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint), 240 ConceptRef(ConceptRef), ArgPackSubstIndex(ArgPackSubstIndex) {} 241 242 /// \brief Get the immediately-declared constraint expression introduced by 243 /// this type-constraint, that is - the constraint expression that is added to 244 /// the associated constraints of the enclosing declaration in practice. getImmediatelyDeclaredConstraint()245 Expr *getImmediatelyDeclaredConstraint() const { 246 return ImmediatelyDeclaredConstraint; 247 } 248 getConceptReference()249 ConceptReference *getConceptReference() const { return ConceptRef; } 250 getArgPackSubstIndex()251 UnsignedOrNone getArgPackSubstIndex() const { return ArgPackSubstIndex; } 252 253 // FIXME: Instead of using these concept related functions the callers should 254 // directly work with the corresponding ConceptReference. getNamedConcept()255 ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } 256 getConceptNameLoc()257 SourceLocation getConceptNameLoc() const { 258 return ConceptRef->getConceptNameLoc(); 259 } 260 hasExplicitTemplateArgs()261 bool hasExplicitTemplateArgs() const { 262 return ConceptRef->hasExplicitTemplateArgs(); 263 } 264 getTemplateArgsAsWritten()265 const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { 266 return ConceptRef->getTemplateArgsAsWritten(); 267 } 268 getTemplateKWLoc()269 SourceLocation getTemplateKWLoc() const { 270 return ConceptRef->getTemplateKWLoc(); 271 } 272 getFoundDecl()273 NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); } 274 getNestedNameSpecifierLoc()275 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { 276 return ConceptRef->getNestedNameSpecifierLoc(); 277 } 278 getConceptNameInfo()279 const DeclarationNameInfo &getConceptNameInfo() const { 280 return ConceptRef->getConceptNameInfo(); 281 } 282 print(llvm::raw_ostream & OS,const PrintingPolicy & Policy)283 void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { 284 ConceptRef->print(OS, Policy); 285 } 286 }; 287 288 } // clang 289 290 #endif // LLVM_CLANG_AST_ASTCONCEPT_H 291