//===--- 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;
 
  bool ContainsErrors = 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);
 
 
 
  bool HasSubstitutionFailure() {
 
    for (const auto &Detail : Details)
 
      if (Detail.second.dyn_cast<SubstitutionDiagnostic *>())
 
        return true;
 
    return false;
 
  }
 
};
 
 
 
/// 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;
 
  bool ContainsErrors : 1;
 
 
 
  const UnsatisfiedConstraintRecord *begin() const {
 
    return getTrailingObjects<UnsatisfiedConstraintRecord>();
 
  }
 
 
 
  const UnsatisfiedConstraintRecord *end() const {
 
    return getTrailingObjects<UnsatisfiedConstraintRecord>() + NumRecords;
 
  }
 
 
 
  ASTConstraintSatisfaction(const ASTContext &C,
 
                            const ConstraintSatisfaction &Satisfaction);
 
  ASTConstraintSatisfaction(const ASTContext &C,
 
                            const ASTConstraintSatisfaction &Satisfaction);
 
 
 
  static ASTConstraintSatisfaction *
 
  Create(const ASTContext &C, const ConstraintSatisfaction &Satisfaction);
 
  static ASTConstraintSatisfaction *
 
  Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &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