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