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 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<UnsatisfiedConstraintRecord>(); 97 } 98 endfinal99 const UnsatisfiedConstraintRecord *end() const { 100 return getTrailingObjects<UnsatisfiedConstraintRecord>() + 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 234 public: TypeConstraint(ConceptReference * ConceptRef,Expr * ImmediatelyDeclaredConstraint)235 TypeConstraint(ConceptReference *ConceptRef, 236 Expr *ImmediatelyDeclaredConstraint) 237 : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint), 238 ConceptRef(ConceptRef) {} 239 240 /// \brief Get the immediately-declared constraint expression introduced by 241 /// this type-constraint, that is - the constraint expression that is added to 242 /// the associated constraints of the enclosing declaration in practice. getImmediatelyDeclaredConstraint()243 Expr *getImmediatelyDeclaredConstraint() const { 244 return ImmediatelyDeclaredConstraint; 245 } 246 getConceptReference()247 ConceptReference *getConceptReference() const { return ConceptRef; } 248 249 // FIXME: Instead of using these concept related functions the callers should 250 // directly work with the corresponding ConceptReference. getNamedConcept()251 ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } 252 getConceptNameLoc()253 SourceLocation getConceptNameLoc() const { 254 return ConceptRef->getConceptNameLoc(); 255 } 256 hasExplicitTemplateArgs()257 bool hasExplicitTemplateArgs() const { 258 return ConceptRef->hasExplicitTemplateArgs(); 259 } 260 getTemplateArgsAsWritten()261 const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { 262 return ConceptRef->getTemplateArgsAsWritten(); 263 } 264 getTemplateKWLoc()265 SourceLocation getTemplateKWLoc() const { 266 return ConceptRef->getTemplateKWLoc(); 267 } 268 getFoundDecl()269 NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); } 270 getNestedNameSpecifierLoc()271 const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { 272 return ConceptRef->getNestedNameSpecifierLoc(); 273 } 274 getConceptNameInfo()275 const DeclarationNameInfo &getConceptNameInfo() const { 276 return ConceptRef->getConceptNameInfo(); 277 } 278 print(llvm::raw_ostream & OS,const PrintingPolicy & Policy)279 void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { 280 ConceptRef->print(OS, Policy); 281 } 282 }; 283 284 } // clang 285 286 #endif // LLVM_CLANG_AST_ASTCONCEPT_H 287