Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:27

0001 //===--- ASTConcept.h - Concepts Related AST Data Structures ----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// \brief This file provides AST data structures related to concepts.
0011 ///
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_AST_ASTCONCEPT_H
0015 #define LLVM_CLANG_AST_ASTCONCEPT_H
0016 
0017 #include "clang/AST/DeclarationName.h"
0018 #include "clang/AST/NestedNameSpecifier.h"
0019 #include "clang/AST/TemplateBase.h"
0020 #include "clang/Basic/SourceLocation.h"
0021 #include "llvm/ADT/FoldingSet.h"
0022 #include "llvm/ADT/PointerUnion.h"
0023 #include "llvm/ADT/SmallVector.h"
0024 #include <utility>
0025 
0026 namespace clang {
0027 
0028 class ConceptDecl;
0029 class Expr;
0030 class NamedDecl;
0031 struct PrintingPolicy;
0032 
0033 /// The result of a constraint satisfaction check, containing the necessary
0034 /// information to diagnose an unsatisfied constraint.
0035 class ConstraintSatisfaction : public llvm::FoldingSetNode {
0036   // The template-like entity that 'owns' the constraint checked here (can be a
0037   // constrained entity or a concept).
0038   const NamedDecl *ConstraintOwner = nullptr;
0039   llvm::SmallVector<TemplateArgument, 4> TemplateArgs;
0040 
0041 public:
0042 
0043   ConstraintSatisfaction() = default;
0044 
0045   ConstraintSatisfaction(const NamedDecl *ConstraintOwner,
0046                          ArrayRef<TemplateArgument> TemplateArgs)
0047       : ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs) {}
0048 
0049   using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
0050   using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
0051 
0052   bool IsSatisfied = false;
0053   bool ContainsErrors = false;
0054 
0055   /// \brief The substituted constraint expr, if the template arguments could be
0056   /// substituted into them, or a diagnostic if substitution resulted in an
0057   /// invalid expression.
0058   llvm::SmallVector<Detail, 4> Details;
0059 
0060   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
0061     Profile(ID, C, ConstraintOwner, TemplateArgs);
0062   }
0063 
0064   static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C,
0065                       const NamedDecl *ConstraintOwner,
0066                       ArrayRef<TemplateArgument> TemplateArgs);
0067 
0068   bool HasSubstitutionFailure() {
0069     for (const auto &Detail : Details)
0070       if (Detail.dyn_cast<SubstitutionDiagnostic *>())
0071         return true;
0072     return false;
0073   }
0074 };
0075 
0076 /// Pairs of unsatisfied atomic constraint expressions along with the
0077 /// substituted constraint expr, if the template arguments could be
0078 /// substituted into them, or a diagnostic if substitution resulted in
0079 /// an invalid expression.
0080 using UnsatisfiedConstraintRecord =
0081     llvm::PointerUnion<Expr *, std::pair<SourceLocation, StringRef> *>;
0082 
0083 /// \brief The result of a constraint satisfaction check, containing the
0084 /// necessary information to diagnose an unsatisfied constraint.
0085 ///
0086 /// This is safe to store in an AST node, as opposed to ConstraintSatisfaction.
0087 struct ASTConstraintSatisfaction final :
0088     llvm::TrailingObjects<ASTConstraintSatisfaction,
0089                           UnsatisfiedConstraintRecord> {
0090   std::size_t NumRecords;
0091   bool IsSatisfied : 1;
0092   bool ContainsErrors : 1;
0093 
0094   const UnsatisfiedConstraintRecord *begin() const {
0095     return getTrailingObjects<UnsatisfiedConstraintRecord>();
0096   }
0097 
0098   const UnsatisfiedConstraintRecord *end() const {
0099     return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords;
0100   }
0101 
0102   ASTConstraintSatisfaction(const ASTContext &C,
0103                             const ConstraintSatisfaction &Satisfaction);
0104   ASTConstraintSatisfaction(const ASTContext &C,
0105                             const ASTConstraintSatisfaction &Satisfaction);
0106 
0107   static ASTConstraintSatisfaction *
0108   Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
0109   static ASTConstraintSatisfaction *
0110   Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction);
0111 };
0112 
0113 /// A reference to a concept and its template args, as it appears in the code.
0114 ///
0115 /// Examples:
0116 ///   template <int X> requires is_even<X> int half = X/2;
0117 ///                             ~~~~~~~~~~ (in ConceptSpecializationExpr)
0118 ///
0119 ///   std::input_iterator auto I = Container.begin();
0120 ///   ~~~~~~~~~~~~~~~~~~~ (in AutoTypeLoc)
0121 ///
0122 ///   template <std::derives_from<Expr> T> void dump();
0123 ///             ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl)
0124 class ConceptReference {
0125   // \brief The optional nested name specifier used when naming the concept.
0126   NestedNameSpecifierLoc NestedNameSpec;
0127 
0128   /// \brief The location of the template keyword, if specified when naming the
0129   /// concept.
0130   SourceLocation TemplateKWLoc;
0131 
0132   /// \brief The concept name used.
0133   DeclarationNameInfo ConceptName;
0134 
0135   /// \brief The declaration found by name lookup when the expression was
0136   /// created.
0137   /// Can differ from NamedConcept when, for example, the concept was found
0138   /// through a UsingShadowDecl.
0139   NamedDecl *FoundDecl;
0140 
0141   /// \brief The concept named.
0142   ConceptDecl *NamedConcept;
0143 
0144   /// \brief The template argument list source info used to specialize the
0145   /// concept.
0146   const ASTTemplateArgumentListInfo *ArgsAsWritten;
0147 
0148   ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
0149                    DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
0150                    ConceptDecl *NamedConcept,
0151                    const ASTTemplateArgumentListInfo *ArgsAsWritten)
0152       : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
0153         ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
0154         NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {}
0155 
0156 public:
0157   static ConceptReference *
0158   Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
0159          SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
0160          NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
0161          const ASTTemplateArgumentListInfo *ArgsAsWritten);
0162 
0163   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
0164     return NestedNameSpec;
0165   }
0166 
0167   const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; }
0168 
0169   SourceLocation getConceptNameLoc() const {
0170     return getConceptNameInfo().getLoc();
0171   }
0172 
0173   SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
0174 
0175   SourceLocation getLocation() const { return getConceptNameLoc(); }
0176 
0177   SourceLocation getBeginLoc() const LLVM_READONLY {
0178     // Note that if the qualifier is null the template KW must also be null.
0179     if (auto QualifierLoc = getNestedNameSpecifierLoc())
0180       return QualifierLoc.getBeginLoc();
0181     return getConceptNameInfo().getBeginLoc();
0182   }
0183 
0184   SourceLocation getEndLoc() const LLVM_READONLY {
0185     return getTemplateArgsAsWritten() &&
0186                    getTemplateArgsAsWritten()->getRAngleLoc().isValid()
0187                ? getTemplateArgsAsWritten()->getRAngleLoc()
0188                : getConceptNameInfo().getEndLoc();
0189   }
0190 
0191   SourceRange getSourceRange() const LLVM_READONLY {
0192     return SourceRange(getBeginLoc(), getEndLoc());
0193   }
0194 
0195   NamedDecl *getFoundDecl() const {
0196     return FoundDecl;
0197   }
0198 
0199   ConceptDecl *getNamedConcept() const {
0200     return NamedConcept;
0201   }
0202 
0203   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
0204     return ArgsAsWritten;
0205   }
0206 
0207   /// \brief Whether or not template arguments were explicitly specified in the
0208   /// concept reference (they might not be in type constraints, for example)
0209   bool hasExplicitTemplateArgs() const {
0210     return ArgsAsWritten != nullptr;
0211   }
0212 
0213   void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
0214   void dump() const;
0215   void dump(llvm::raw_ostream &) const;
0216 };
0217 
0218 /// Models the abbreviated syntax to constrain a template type parameter:
0219 ///   template <convertible_to<string> T> void print(T object);
0220 ///             ~~~~~~~~~~~~~~~~~~~~~~
0221 /// Semantically, this adds an "immediately-declared constraint" with extra arg:
0222 ///    requires convertible_to<T, string>
0223 ///
0224 /// In the C++ grammar, a type-constraint is also used for auto types:
0225 ///    convertible_to<string> auto X = ...;
0226 /// We do *not* model these as TypeConstraints, but AutoType(Loc) directly.
0227 class TypeConstraint {
0228   /// \brief The immediately-declared constraint expression introduced by this
0229   /// type-constraint.
0230   Expr *ImmediatelyDeclaredConstraint = nullptr;
0231   ConceptReference *ConceptRef;
0232 
0233 public:
0234   TypeConstraint(ConceptReference *ConceptRef,
0235                  Expr *ImmediatelyDeclaredConstraint)
0236       : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint),
0237         ConceptRef(ConceptRef) {}
0238 
0239   /// \brief Get the immediately-declared constraint expression introduced by
0240   /// this type-constraint, that is - the constraint expression that is added to
0241   /// the associated constraints of the enclosing declaration in practice.
0242   Expr *getImmediatelyDeclaredConstraint() const {
0243     return ImmediatelyDeclaredConstraint;
0244   }
0245 
0246   ConceptReference *getConceptReference() const { return ConceptRef; }
0247 
0248   // FIXME: Instead of using these concept related functions the callers should
0249   // directly work with the corresponding ConceptReference.
0250   ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
0251 
0252   SourceLocation getConceptNameLoc() const {
0253     return ConceptRef->getConceptNameLoc();
0254   }
0255 
0256   bool hasExplicitTemplateArgs() const {
0257     return ConceptRef->hasExplicitTemplateArgs();
0258   }
0259 
0260   const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
0261     return ConceptRef->getTemplateArgsAsWritten();
0262   }
0263 
0264   SourceLocation getTemplateKWLoc() const {
0265     return ConceptRef->getTemplateKWLoc();
0266   }
0267 
0268   NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); }
0269 
0270   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
0271     return ConceptRef->getNestedNameSpecifierLoc();
0272   }
0273 
0274   const DeclarationNameInfo &getConceptNameInfo() const {
0275     return ConceptRef->getConceptNameInfo();
0276   }
0277 
0278   void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const {
0279     ConceptRef->print(OS, Policy);
0280   }
0281 };
0282 
0283 } // clang
0284 
0285 #endif // LLVM_CLANG_AST_ASTCONCEPT_H