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