| //===--- ASTConcept.h - Concepts Related AST Data Structures ----*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief This file provides AST data structures related to concepts. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_ASTCONCEPT_H |
| #define LLVM_CLANG_AST_ASTCONCEPT_H |
| |
| #include "clang/AST/Expr.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include <utility> |
| |
| namespace clang { |
| class ConceptDecl; |
| |
| /// The result of a constraint satisfaction check, containing the necessary |
| /// information to diagnose an unsatisfied constraint. |
| class ConstraintSatisfaction : public llvm::FoldingSetNode { |
| // The template-like entity that 'owns' the constraint checked here (can be a |
| // constrained entity or a concept). |
| const NamedDecl *ConstraintOwner = nullptr; |
| llvm::SmallVector<TemplateArgument, 4> TemplateArgs; |
| |
| public: |
| |
| ConstraintSatisfaction() = default; |
| |
| ConstraintSatisfaction(const NamedDecl *ConstraintOwner, |
| ArrayRef<TemplateArgument> TemplateArgs) : |
| ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(), |
| TemplateArgs.end()) { } |
| |
| using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>; |
| using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>; |
| |
| bool IsSatisfied = false; |
| |
| /// \brief Pairs of unsatisfied atomic constraint expressions along with the |
| /// substituted constraint expr, if the template arguments could be |
| /// substituted into them, or a diagnostic if substitution resulted in an |
| /// invalid expression. |
| llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details; |
| |
| void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) { |
| Profile(ID, C, ConstraintOwner, TemplateArgs); |
| } |
| |
| static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C, |
| const NamedDecl *ConstraintOwner, |
| ArrayRef<TemplateArgument> TemplateArgs); |
| }; |
| |
| /// Pairs of unsatisfied atomic constraint expressions along with the |
| /// substituted constraint expr, if the template arguments could be |
| /// substituted into them, or a diagnostic if substitution resulted in |
| /// an invalid expression. |
| using UnsatisfiedConstraintRecord = |
| std::pair<const Expr *, |
| llvm::PointerUnion<Expr *, |
| std::pair<SourceLocation, StringRef> *>>; |
| |
| /// \brief The result of a constraint satisfaction check, containing the |
| /// necessary information to diagnose an unsatisfied constraint. |
| /// |
| /// This is safe to store in an AST node, as opposed to ConstraintSatisfaction. |
| struct ASTConstraintSatisfaction final : |
| llvm::TrailingObjects<ASTConstraintSatisfaction, |
| UnsatisfiedConstraintRecord> { |
| std::size_t NumRecords; |
| bool IsSatisfied : 1; |
| |
| const UnsatisfiedConstraintRecord *begin() const { |
| return getTrailingObjects<UnsatisfiedConstraintRecord>(); |
| } |
| |
| const UnsatisfiedConstraintRecord *end() const { |
| return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords; |
| } |
| |
| ASTConstraintSatisfaction(const ASTContext &C, |
| const ConstraintSatisfaction &Satisfaction); |
| |
| static ASTConstraintSatisfaction * |
| Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction); |
| }; |
| |
| /// \brief Common data class for constructs that reference concepts with |
| /// template arguments. |
| class ConceptReference { |
| protected: |
| // \brief The optional nested name specifier used when naming the concept. |
| NestedNameSpecifierLoc NestedNameSpec; |
| |
| /// \brief The location of the template keyword, if specified when naming the |
| /// concept. |
| SourceLocation TemplateKWLoc; |
| |
| /// \brief The concept name used. |
| DeclarationNameInfo ConceptName; |
| |
| /// \brief The declaration found by name lookup when the expression was |
| /// created. |
| /// Can differ from NamedConcept when, for example, the concept was found |
| /// through a UsingShadowDecl. |
| NamedDecl *FoundDecl; |
| |
| /// \brief The concept named. |
| ConceptDecl *NamedConcept; |
| |
| /// \brief The template argument list source info used to specialize the |
| /// concept. |
| const ASTTemplateArgumentListInfo *ArgsAsWritten; |
| |
| public: |
| ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, |
| DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, |
| ConceptDecl *NamedConcept, |
| const ASTTemplateArgumentListInfo *ArgsAsWritten) |
| : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), |
| ConceptName(ConceptNameInfo), FoundDecl(FoundDecl), |
| NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {} |
| |
| ConceptReference() |
| : FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {} |
| |
| const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { |
| return NestedNameSpec; |
| } |
| |
| const DeclarationNameInfo &getConceptNameInfo() const { return ConceptName; } |
| |
| SourceLocation getConceptNameLoc() const { |
| return getConceptNameInfo().getLoc(); |
| } |
| |
| SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } |
| |
| NamedDecl *getFoundDecl() const { |
| return FoundDecl; |
| } |
| |
| ConceptDecl *getNamedConcept() const { |
| return NamedConcept; |
| } |
| |
| const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { |
| return ArgsAsWritten; |
| } |
| |
| /// \brief Whether or not template arguments were explicitly specified in the |
| /// concept reference (they might not be in type constraints, for example) |
| bool hasExplicitTemplateArgs() const { |
| return ArgsAsWritten != nullptr; |
| } |
| }; |
| |
| class TypeConstraint : public ConceptReference { |
| /// \brief The immediately-declared constraint expression introduced by this |
| /// type-constraint. |
| Expr *ImmediatelyDeclaredConstraint = nullptr; |
| |
| public: |
| TypeConstraint(NestedNameSpecifierLoc NNS, |
| DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, |
| ConceptDecl *NamedConcept, |
| const ASTTemplateArgumentListInfo *ArgsAsWritten, |
| Expr *ImmediatelyDeclaredConstraint) : |
| ConceptReference(NNS, /*TemplateKWLoc=*/SourceLocation(), ConceptNameInfo, |
| FoundDecl, NamedConcept, ArgsAsWritten), |
| ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint) {} |
| |
| /// \brief Get the immediately-declared constraint expression introduced by |
| /// this type-constraint, that is - the constraint expression that is added to |
| /// the associated constraints of the enclosing declaration in practice. |
| Expr *getImmediatelyDeclaredConstraint() const { |
| return ImmediatelyDeclaredConstraint; |
| } |
| |
| void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const; |
| }; |
| |
| } // clang |
| |
| #endif // LLVM_CLANG_AST_ASTCONCEPT_H |