//===- DeclTemplate.h - Classes for representing C++ templates --*- 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
 
/// Defines the C++ template declaration subclasses.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H
 
#define LLVM_CLANG_AST_DECLTEMPLATE_H
 
 
 
#include "clang/AST/ASTConcept.h"
 
#include "clang/AST/ASTContext.h"
 
#include "clang/AST/Decl.h"
 
#include "clang/AST/DeclBase.h"
 
#include "clang/AST/DeclCXX.h"
 
#include "clang/AST/DeclarationName.h"
 
#include "clang/AST/Redeclarable.h"
 
#include "clang/AST/TemplateBase.h"
 
#include "clang/AST/Type.h"
 
#include "clang/Basic/LLVM.h"
 
#include "clang/Basic/SourceLocation.h"
 
#include "clang/Basic/Specifiers.h"
 
#include "llvm/ADT/ArrayRef.h"
 
#include "llvm/ADT/FoldingSet.h"
 
#include "llvm/ADT/PointerIntPair.h"
 
#include "llvm/ADT/PointerUnion.h"
 
#include "llvm/ADT/iterator.h"
 
#include "llvm/ADT/iterator_range.h"
 
#include "llvm/Support/Casting.h"
 
#include "llvm/Support/Compiler.h"
 
#include "llvm/Support/TrailingObjects.h"
 
#include <cassert>
 
#include <cstddef>
 
#include <cstdint>
 
#include <iterator>
 
#include <optional>
 
#include <utility>
 
 
 
namespace clang {
 
 
 
enum BuiltinTemplateKind : int;
 
class ClassTemplateDecl;
 
class ClassTemplatePartialSpecializationDecl;
 
class Expr;
 
class FunctionTemplateDecl;
 
class IdentifierInfo;
 
class NonTypeTemplateParmDecl;
 
class TemplateDecl;
 
class TemplateTemplateParmDecl;
 
class TemplateTypeParmDecl;
 
class ConceptDecl;
 
class UnresolvedSetImpl;
 
class VarTemplateDecl;
 
class VarTemplatePartialSpecializationDecl;
 
 
 
/// Stores a template parameter of any kind.
 
using TemplateParameter =
 
    llvm::PointerUnion<TemplateTypeParmDecl *, NonTypeTemplateParmDecl *,
 
                       TemplateTemplateParmDecl *>;
 
 
 
NamedDecl *getAsNamedDecl(TemplateParameter P);
 
 
 
/// Stores a list of template parameters for a TemplateDecl and its
 
/// derived classes.
 
class TemplateParameterList final
 
    : private llvm::TrailingObjects<TemplateParameterList, NamedDecl *,
 
                                    Expr *> {
 
  /// The location of the 'template' keyword.
 
  SourceLocation TemplateLoc;
 
 
 
  /// The locations of the '<' and '>' angle brackets.
 
  SourceLocation LAngleLoc, RAngleLoc;
 
 
 
  /// The number of template parameters in this template
 
  /// parameter list.
 
  unsigned NumParams : 29;
 
 
 
  /// Whether this template parameter list contains an unexpanded parameter
 
  /// pack.
 
  unsigned ContainsUnexpandedParameterPack : 1;
 
 
 
  /// Whether this template parameter list has a requires clause.
 
  unsigned HasRequiresClause : 1;
 
 
 
  /// Whether any of the template parameters has constrained-parameter
 
  /// constraint-expression.
 
  unsigned HasConstrainedParameters : 1;
 
 
 
protected:
 
  TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc,
 
                        SourceLocation LAngleLoc, ArrayRef<NamedDecl *> Params,
 
                        SourceLocation RAngleLoc, Expr *RequiresClause);
 
 
 
  size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
 
    return NumParams;
 
  }
 
 
 
  size_t numTrailingObjects(OverloadToken<Expr *>) const {
 
    return HasRequiresClause ? 1 : 0;
 
  }
 
 
 
public:
 
  template <size_t N, bool HasRequiresClause>
 
  friend class FixedSizeTemplateParameterListStorage;
 
  friend TrailingObjects;
 
 
 
  static TemplateParameterList *Create(const ASTContext &C,
 
                                       SourceLocation TemplateLoc,
 
                                       SourceLocation LAngleLoc,
 
                                       ArrayRef<NamedDecl *> Params,
 
                                       SourceLocation RAngleLoc,
 
                                       Expr *RequiresClause);
 
 
 
  /// Iterates through the template parameters in this list.
 
  using iterator = NamedDecl **;
 
 
 
  /// Iterates through the template parameters in this list.
 
  using const_iterator = NamedDecl * const *;
 
 
 
  iterator begin() { return getTrailingObjects<NamedDecl *>(); }
 
  const_iterator begin() const { return getTrailingObjects<NamedDecl *>(); }
 
  iterator end() { return begin() + NumParams; }
 
  const_iterator end() const { return begin() + NumParams; }
 
 
 
  unsigned size() const { return NumParams; }
 
 
 
  ArrayRef<NamedDecl *> asArray() { return llvm::ArrayRef(begin(), end()); }
 
  ArrayRef<const NamedDecl*> asArray() const {
 
    return llvm::ArrayRef(begin(), size());
 
  }
 
 
 
  NamedDecl* getParam(unsigned Idx) {
 
    assert(Idx < size() && "Template parameter index out-of-range");
 
    return begin()[Idx];
 
  }
 
  const NamedDecl* getParam(unsigned Idx) const {
 
    assert(Idx < size() && "Template parameter index out-of-range");
 
    return begin()[Idx];
 
  }
 
 
 
  /// Returns the minimum number of arguments needed to form a
 
  /// template specialization.
 
  ///
 
  /// This may be fewer than the number of template parameters, if some of
 
  /// the parameters have default arguments or if there is a parameter pack.
 
  unsigned getMinRequiredArguments() const;
 
 
 
  /// Get the depth of this template parameter list in the set of
 
  /// template parameter lists.
 
  ///
 
  /// The first template parameter list in a declaration will have depth 0,
 
  /// the second template parameter list will have depth 1, etc.
 
  unsigned getDepth() const;
 
 
 
  /// Determine whether this template parameter list contains an
 
  /// unexpanded parameter pack.
 
  bool containsUnexpandedParameterPack() const;
 
 
 
  /// Determine whether this template parameter list contains a parameter pack.
 
  bool hasParameterPack() const {
 
    for (const NamedDecl *P : asArray())
 
      if (P->isParameterPack())
 
        return true;
 
    return false;
 
  }
 
 
 
  /// The constraint-expression of the associated requires-clause.
 
  Expr *getRequiresClause() {
 
    return HasRequiresClause ? getTrailingObjects<Expr *>()[0] : nullptr;
 
  }
 
 
 
  /// The constraint-expression of the associated requires-clause.
 
  const Expr *getRequiresClause() const {
 
    return HasRequiresClause ? getTrailingObjects<Expr *>()[0] : nullptr;
 
  }
 
 
 
  /// \brief All associated constraints derived from this template parameter
 
  /// list, including the requires clause and any constraints derived from
 
  /// constrained-parameters.
 
  ///
 
  /// The constraints in the resulting list are to be treated as if in a
 
  /// conjunction ("and").
 
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
 
 
 
  bool hasAssociatedConstraints() const;
 
 
 
  SourceLocation getTemplateLoc() const { return TemplateLoc; }
 
  SourceLocation getLAngleLoc() const { return LAngleLoc; }
 
  SourceLocation getRAngleLoc() const { return RAngleLoc; }
 
 
 
  SourceRange getSourceRange() const LLVM_READONLY {
 
    return SourceRange(TemplateLoc, RAngleLoc);
 
  }
 
 
 
  void print(raw_ostream &Out, const ASTContext &Context,
 
             bool OmitTemplateKW = false) const;
 
  void print(raw_ostream &Out, const ASTContext &Context,
 
             const PrintingPolicy &Policy, bool OmitTemplateKW = false) const;
 
 
 
  static bool shouldIncludeTypeForArgument(const PrintingPolicy &Policy,
 
                                           const TemplateParameterList *TPL,
 
                                           unsigned Idx);
 
};
 
 
 
/// Stores a list of template parameters and the associated
 
/// requires-clause (if any) for a TemplateDecl and its derived classes.
 
/// Suitable for creating on the stack.
 
template <size_t N, bool HasRequiresClause>
 
class FixedSizeTemplateParameterListStorage
 
    : public TemplateParameterList::FixedSizeStorageOwner {
 
  typename TemplateParameterList::FixedSizeStorage<
 
      NamedDecl *, Expr *>::with_counts<
 
      N, HasRequiresClause ? 1u : 0u
 
      >::type storage;
 
 
 
public:
 
  FixedSizeTemplateParameterListStorage(const ASTContext &C,
 
                                        SourceLocation TemplateLoc,
 
                                        SourceLocation LAngleLoc,
 
                                        ArrayRef<NamedDecl *> Params,
 
                                        SourceLocation RAngleLoc,
 
                                        Expr *RequiresClause)
 
      : FixedSizeStorageOwner(
 
            (assert(N == Params.size()),
 
             assert(HasRequiresClause == (RequiresClause != nullptr)),
 
             new (static_cast<void *>(&storage)) TemplateParameterList(C,
 
                 TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause))) {}
 
};
 
 
 
/// A template argument list.
 
class TemplateArgumentList final
 
    : private llvm::TrailingObjects<TemplateArgumentList, TemplateArgument> {
 
  /// The template argument list.
 
  const TemplateArgument *Arguments;
 
 
 
  /// The number of template arguments in this template
 
  /// argument list.
 
  unsigned NumArguments;
 
 
 
  // Constructs an instance with an internal Argument list, containing
 
  // a copy of the Args array. (Called by CreateCopy)
 
  TemplateArgumentList(ArrayRef<TemplateArgument> Args);
 
 
 
public:
 
  friend TrailingObjects;
 
 
 
  TemplateArgumentList(const TemplateArgumentList &) = delete;
 
  TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
 
 
 
  /// Type used to indicate that the template argument list itself is a
 
  /// stack object. It does not own its template arguments.
 
  enum OnStackType { OnStack };
 
 
 
  /// Create a new template argument list that copies the given set of
 
  /// template arguments.
 
  static TemplateArgumentList *CreateCopy(ASTContext &Context,
 
                                          ArrayRef<TemplateArgument> Args);
 
 
 
  /// Construct a new, temporary template argument list on the stack.
 
  ///
 
  /// The template argument list does not own the template arguments
 
  /// provided.
 
  explicit TemplateArgumentList(OnStackType, ArrayRef<TemplateArgument> Args)
 
      : Arguments(Args.data()), NumArguments(Args.size()) {}
 
 
 
  /// Produces a shallow copy of the given template argument list.
 
  ///
 
  /// This operation assumes that the input argument list outlives it.
 
  /// This takes the list as a pointer to avoid looking like a copy
 
  /// constructor, since this really isn't safe to use that way.
 
  explicit TemplateArgumentList(const TemplateArgumentList *Other)
 
      : Arguments(Other->data()), NumArguments(Other->size()) {}
 
 
 
  /// Retrieve the template argument at a given index.
 
  const TemplateArgument &get(unsigned Idx) const {
 
    assert(Idx < NumArguments && "Invalid template argument index");
 
    return data()[Idx];
 
  }
 
 
 
  /// Retrieve the template argument at a given index.
 
  const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
 
 
 
  /// Produce this as an array ref.
 
  ArrayRef<TemplateArgument> asArray() const {
 
    return llvm::ArrayRef(data(), size());
 
  }
 
 
 
  /// Retrieve the number of template arguments in this
 
  /// template argument list.
 
  unsigned size() const { return NumArguments; }
 
 
 
  /// Retrieve a pointer to the template argument list.
 
  const TemplateArgument *data() const { return Arguments; }
 
};
 
 
 
void *allocateDefaultArgStorageChain(const ASTContext &C);
 
 
 
/// Storage for a default argument. This is conceptually either empty, or an
 
/// argument value, or a pointer to a previous declaration that had a default
 
/// argument.
 
///
 
/// However, this is complicated by modules: while we require all the default
 
/// arguments for a template to be equivalent, there may be more than one, and
 
/// we need to track all the originating parameters to determine if the default
 
/// argument is visible.
 
template<typename ParmDecl, typename ArgType>
 
class DefaultArgStorage {
 
  /// Storage for both the value *and* another parameter from which we inherit
 
  /// the default argument. This is used when multiple default arguments for a
 
  /// parameter are merged together from different modules.
 
  struct Chain {
 
    ParmDecl *PrevDeclWithDefaultArg;
 
    ArgType Value;
 
  };
 
  static_assert(sizeof(Chain) == sizeof(void *) * 2,
 
                "non-pointer argument type?");
 
 
 
  llvm::PointerUnion<ArgType, ParmDecl*, Chain*> ValueOrInherited;
 
 
 
  static ParmDecl *getParmOwningDefaultArg(ParmDecl *Parm) {
 
    const DefaultArgStorage &Storage = Parm->getDefaultArgStorage();
 
    if (auto *Prev = Storage.ValueOrInherited.template dyn_cast<ParmDecl *>())
 
      Parm = Prev;
 
    assert(!Parm->getDefaultArgStorage()
 
                .ValueOrInherited.template is<ParmDecl *>() &&
 
           "should only be one level of indirection");
 
    return Parm;
 
  }
 
 
 
public:
 
  DefaultArgStorage() : ValueOrInherited(ArgType()) {}
 
 
 
  /// Determine whether there is a default argument for this parameter.
 
  bool isSet() const { return !ValueOrInherited.isNull(); }
 
 
 
  /// Determine whether the default argument for this parameter was inherited
 
  /// from a previous declaration of the same entity.
 
  bool isInherited() const { return ValueOrInherited.template is<ParmDecl*>(); }
 
 
 
  /// Get the default argument's value. This does not consider whether the
 
  /// default argument is visible.
 
  ArgType get() const {
 
    const DefaultArgStorage *Storage = this;
 
    if (const auto *Prev = ValueOrInherited.template dyn_cast<ParmDecl *>())
 
      Storage = &Prev->getDefaultArgStorage();
 
    if (const auto *C = Storage->ValueOrInherited.template dyn_cast<Chain *>())
 
      return C->Value;
 
    return Storage->ValueOrInherited.template get<ArgType>();
 
  }
 
 
 
  /// Get the parameter from which we inherit the default argument, if any.
 
  /// This is the parameter on which the default argument was actually written.
 
  const ParmDecl *getInheritedFrom() const {
 
    if (const auto *D = ValueOrInherited.template dyn_cast<ParmDecl *>())
 
      return D;
 
    if (const auto *C = ValueOrInherited.template dyn_cast<Chain *>())
 
      return C->PrevDeclWithDefaultArg;
 
    return nullptr;
 
  }
 
 
 
  /// Set the default argument.
 
  void set(ArgType Arg) {
 
    assert(!isSet() && "default argument already set");
 
    ValueOrInherited = Arg;
 
  }
 
 
 
  /// Set that the default argument was inherited from another parameter.
 
  void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) {
 
    InheritedFrom = getParmOwningDefaultArg(InheritedFrom);
 
    if (!isSet())
 
      ValueOrInherited = InheritedFrom;
 
    else if (auto *D = ValueOrInherited.template dyn_cast<ParmDecl *>()) {
 
      assert(C.isSameDefaultTemplateArgument(D, InheritedFrom));
 
      ValueOrInherited =
 
          new (allocateDefaultArgStorageChain(C)) Chain{InheritedFrom, get()};
 
    } else if (auto *Inherited =
 
                   ValueOrInherited.template dyn_cast<Chain *>()) {
 
      assert(C.isSameDefaultTemplateArgument(Inherited->PrevDeclWithDefaultArg,
 
                                             InheritedFrom));
 
      Inherited->PrevDeclWithDefaultArg = InheritedFrom;
 
    } else
 
      ValueOrInherited = new (allocateDefaultArgStorageChain(C))
 
          Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()};
 
  }
 
 
 
  /// Remove the default argument, even if it was inherited.
 
  void clear() {
 
    ValueOrInherited = ArgType();
 
  }
 
};
 
 
 
//===----------------------------------------------------------------------===//
 
// Kinds of Templates
 
//===----------------------------------------------------------------------===//
 
 
 
/// \brief The base class of all kinds of template declarations (e.g.,
 
/// class, function, etc.).
 
///
 
/// The TemplateDecl class stores the list of template parameters and a
 
/// reference to the templated scoped declaration: the underlying AST node.
 
class TemplateDecl : public NamedDecl {
 
  void anchor() override;
 
 
 
protected:
 
  // Construct a template decl with name, parameters, and templated element.
 
  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
 
               TemplateParameterList *Params, NamedDecl *Decl);
 
 
 
  // Construct a template decl with the given name and parameters.
 
  // Used when there is no templated element (e.g., for tt-params).
 
  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
 
               TemplateParameterList *Params)
 
      : TemplateDecl(DK, DC, L, Name, Params, nullptr) {}
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  /// Get the list of template parameters
 
  TemplateParameterList *getTemplateParameters() const {
 
    return TemplateParams;
 
  }
 
 
 
  /// \brief Get the total constraint-expression associated with this template,
 
  /// including constraint-expressions derived from the requires-clause,
 
  /// trailing requires-clause (for functions and methods) and constrained
 
  /// template parameters.
 
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
 
 
 
  bool hasAssociatedConstraints() const;
 
 
 
  /// Get the underlying, templated declaration.
 
  NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
 
 
 
  // Should a specialization behave like an alias for another type.
 
  bool isTypeAlias() const;
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K >= firstTemplate && K <= lastTemplate;
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY {
 
    return SourceRange(getTemplateParameters()->getTemplateLoc(),
 
                       TemplatedDecl->getSourceRange().getEnd());
 
  }
 
 
 
protected:
 
  NamedDecl *TemplatedDecl;
 
  TemplateParameterList *TemplateParams;
 
 
 
public:
 
  void setTemplateParameters(TemplateParameterList *TParams) {
 
    TemplateParams = TParams;
 
  }
 
 
 
  /// Initialize the underlying templated declaration.
 
  void init(NamedDecl *NewTemplatedDecl) {
 
    if (TemplatedDecl)
 
      assert(TemplatedDecl == NewTemplatedDecl && "Inconsistent TemplatedDecl");
 
    else
 
      TemplatedDecl = NewTemplatedDecl;
 
  }
 
};
 
 
 
/// Provides information about a function template specialization,
 
/// which is a FunctionDecl that has been explicitly specialization or
 
/// instantiated from a function template.
 
class FunctionTemplateSpecializationInfo final
 
    : public llvm::FoldingSetNode,
 
      private llvm::TrailingObjects<FunctionTemplateSpecializationInfo,
 
                                    MemberSpecializationInfo *> {
 
  /// The function template specialization that this structure describes and a
 
  /// flag indicating if the function is a member specialization.
 
  llvm::PointerIntPair<FunctionDecl *, 1, bool> Function;
 
 
 
  /// The function template from which this function template
 
  /// specialization was generated.
 
  ///
 
  /// The two bits contain the top 4 values of TemplateSpecializationKind.
 
  llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
 
 
 
public:
 
  /// The template arguments used to produce the function template
 
  /// specialization from the function template.
 
  const TemplateArgumentList *TemplateArguments;
 
 
 
  /// The template arguments as written in the sources, if provided.
 
  /// FIXME: Normally null; tail-allocate this.
 
  const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
 
 
 
  /// The point at which this function template specialization was
 
  /// first instantiated.
 
  SourceLocation PointOfInstantiation;
 
 
 
private:
 
  FunctionTemplateSpecializationInfo(
 
      FunctionDecl *FD, FunctionTemplateDecl *Template,
 
      TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
 
      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
 
      SourceLocation POI, MemberSpecializationInfo *MSInfo)
 
      : Function(FD, MSInfo ? true : false), Template(Template, TSK - 1),
 
        TemplateArguments(TemplateArgs),
 
        TemplateArgumentsAsWritten(TemplateArgsAsWritten),
 
        PointOfInstantiation(POI) {
 
    if (MSInfo)
 
      getTrailingObjects<MemberSpecializationInfo *>()[0] = MSInfo;
 
  }
 
 
 
  size_t numTrailingObjects(OverloadToken<MemberSpecializationInfo*>) const {
 
    return Function.getInt();
 
  }
 
 
 
public:
 
  friend TrailingObjects;
 
 
 
  static FunctionTemplateSpecializationInfo *
 
  Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
 
         TemplateSpecializationKind TSK,
 
         const TemplateArgumentList *TemplateArgs,
 
         const TemplateArgumentListInfo *TemplateArgsAsWritten,
 
         SourceLocation POI, MemberSpecializationInfo *MSInfo);
 
 
 
  /// Retrieve the declaration of the function template specialization.
 
  FunctionDecl *getFunction() const { return Function.getPointer(); }
 
 
 
  /// Retrieve the template from which this function was specialized.
 
  FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); }
 
 
 
  /// Determine what kind of template specialization this is.
 
  TemplateSpecializationKind getTemplateSpecializationKind() const {
 
    return (TemplateSpecializationKind)(Template.getInt() + 1);
 
  }
 
 
 
  bool isExplicitSpecialization() const {
 
    return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
 
  }
 
 
 
  /// True if this declaration is an explicit specialization,
 
  /// explicit instantiation declaration, or explicit instantiation
 
  /// definition.
 
  bool isExplicitInstantiationOrSpecialization() const {
 
    return isTemplateExplicitInstantiationOrSpecialization(
 
        getTemplateSpecializationKind());
 
  }
 
 
 
  /// Set the template specialization kind.
 
  void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
 
    assert(TSK != TSK_Undeclared &&
 
         "Cannot encode TSK_Undeclared for a function template specialization");
 
    Template.setInt(TSK - 1);
 
  }
 
 
 
  /// Retrieve the first point of instantiation of this function
 
  /// template specialization.
 
  ///
 
  /// The point of instantiation may be an invalid source location if this
 
  /// function has yet to be instantiated.
 
  SourceLocation getPointOfInstantiation() const {
 
    return PointOfInstantiation;
 
  }
 
 
 
  /// Set the (first) point of instantiation of this function template
 
  /// specialization.
 
  void setPointOfInstantiation(SourceLocation POI) {
 
    PointOfInstantiation = POI;
 
  }
 
 
 
  /// Get the specialization info if this function template specialization is
 
  /// also a member specialization:
 
  ///
 
  /// \code
 
  /// template<typename> struct A {
 
  ///   template<typename> void f();
 
  ///   template<> void f<int>(); // ClassScopeFunctionSpecializationDecl
 
  /// };
 
  /// \endcode
 
  ///
 
  /// Here, A<int>::f<int> is a function template specialization that is
 
  /// an explicit specialization of A<int>::f, but it's also a member
 
  /// specialization (an implicit instantiation in this case) of A::f<int>.
 
  /// Further:
 
  ///
 
  /// \code
 
  /// template<> template<> void A<int>::f<int>() {}
 
  /// \endcode
 
  ///
 
  /// ... declares a function template specialization that is an explicit
 
  /// specialization of A<int>::f, and is also an explicit member
 
  /// specialization of A::f<int>.
 
  ///
 
  /// Note that the TemplateSpecializationKind of the MemberSpecializationInfo
 
  /// need not be the same as that returned by getTemplateSpecializationKind(),
 
  /// and represents the relationship between the function and the class-scope
 
  /// explicit specialization in the original templated class -- whereas our
 
  /// TemplateSpecializationKind represents the relationship between the
 
  /// function and the function template, and should always be
 
  /// TSK_ExplicitSpecialization whenever we have MemberSpecializationInfo.
 
  MemberSpecializationInfo *getMemberSpecializationInfo() const {
 
    return numTrailingObjects(OverloadToken<MemberSpecializationInfo *>())
 
               ? getTrailingObjects<MemberSpecializationInfo *>()[0]
 
               : nullptr;
 
  }
 
 
 
  void Profile(llvm::FoldingSetNodeID &ID) {
 
    Profile(ID, TemplateArguments->asArray(), getFunction()->getASTContext());
 
  }
 
 
 
  static void
 
  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
 
          ASTContext &Context) {
 
    ID.AddInteger(TemplateArgs.size());
 
    for (const TemplateArgument &TemplateArg : TemplateArgs)
 
      TemplateArg.Profile(ID, Context);
 
  }
 
};
 
 
 
/// Provides information a specialization of a member of a class
 
/// template, which may be a member function, static data member,
 
/// member class or member enumeration.
 
class MemberSpecializationInfo {
 
  // The member declaration from which this member was instantiated, and the
 
  // manner in which the instantiation occurred (in the lower two bits).
 
  llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK;
 
 
 
  // The point at which this member was first instantiated.
 
  SourceLocation PointOfInstantiation;
 
 
 
public:
 
  explicit
 
  MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK,
 
                           SourceLocation POI = SourceLocation())
 
      : MemberAndTSK(IF, TSK - 1), PointOfInstantiation(POI) {
 
    assert(TSK != TSK_Undeclared &&
 
           "Cannot encode undeclared template specializations for members");
 
  }
 
 
 
  /// Retrieve the member declaration from which this member was
 
  /// instantiated.
 
  NamedDecl *getInstantiatedFrom() const { return MemberAndTSK.getPointer(); }
 
 
 
  /// Determine what kind of template specialization this is.
 
  TemplateSpecializationKind getTemplateSpecializationKind() const {
 
    return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
 
  }
 
 
 
  bool isExplicitSpecialization() const {
 
    return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
 
  }
 
 
 
  /// Set the template specialization kind.
 
  void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
 
    assert(TSK != TSK_Undeclared &&
 
           "Cannot encode undeclared template specializations for members");
 
    MemberAndTSK.setInt(TSK - 1);
 
  }
 
 
 
  /// Retrieve the first point of instantiation of this member.
 
  /// If the point of instantiation is an invalid location, then this member
 
  /// has not yet been instantiated.
 
  SourceLocation getPointOfInstantiation() const {
 
    return PointOfInstantiation;
 
  }
 
 
 
  /// Set the first point of instantiation.
 
  void setPointOfInstantiation(SourceLocation POI) {
 
    PointOfInstantiation = POI;
 
  }
 
};
 
 
 
/// Provides information about a dependent function-template
 
/// specialization declaration.
 
///
 
/// Since explicit function template specialization and instantiation
 
/// declarations can only appear in namespace scope, and you can only
 
/// specialize a member of a fully-specialized class, the only way to
 
/// get one of these is in a friend declaration like the following:
 
///
 
/// \code
 
///   template \<class T> void foo(T);
 
///   template \<class T> class A {
 
///     friend void foo<>(T);
 
///   };
 
/// \endcode
 
class DependentFunctionTemplateSpecializationInfo final
 
    : private llvm::TrailingObjects<DependentFunctionTemplateSpecializationInfo,
 
                                    TemplateArgumentLoc,
 
                                    FunctionTemplateDecl *> {
 
  /// The number of potential template candidates.
 
  unsigned NumTemplates;
 
 
 
  /// The number of template arguments.
 
  unsigned NumArgs;
 
 
 
  /// The locations of the left and right angle brackets.
 
  SourceRange AngleLocs;
 
 
 
  size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const {
 
    return NumArgs;
 
  }
 
  size_t numTrailingObjects(OverloadToken<FunctionTemplateDecl *>) const {
 
    return NumTemplates;
 
  }
 
 
 
  DependentFunctionTemplateSpecializationInfo(
 
                                 const UnresolvedSetImpl &Templates,
 
                                 const TemplateArgumentListInfo &TemplateArgs);
 
 
 
public:
 
  friend TrailingObjects;
 
 
 
  static DependentFunctionTemplateSpecializationInfo *
 
  Create(ASTContext &Context, const UnresolvedSetImpl &Templates,
 
         const TemplateArgumentListInfo &TemplateArgs);
 
 
 
  /// Returns the number of function templates that this might
 
  /// be a specialization of.
 
  unsigned getNumTemplates() const { return NumTemplates; }
 
 
 
  /// Returns the i'th template candidate.
 
  FunctionTemplateDecl *getTemplate(unsigned I) const {
 
    assert(I < getNumTemplates() && "template index out of range");
 
    return getTrailingObjects<FunctionTemplateDecl *>()[I];
 
  }
 
 
 
  /// Returns the explicit template arguments that were given.
 
  const TemplateArgumentLoc *getTemplateArgs() const {
 
    return getTrailingObjects<TemplateArgumentLoc>();
 
  }
 
 
 
  /// Returns the number of explicit template arguments that were given.
 
  unsigned getNumTemplateArgs() const { return NumArgs; }
 
 
 
  llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
 
    return llvm::ArrayRef(getTemplateArgs(), getNumTemplateArgs());
 
  }
 
 
 
  /// Returns the nth template argument.
 
  const TemplateArgumentLoc &getTemplateArg(unsigned I) const {
 
    assert(I < getNumTemplateArgs() && "template arg index out of range");
 
    return getTemplateArgs()[I];
 
  }
 
 
 
  SourceLocation getLAngleLoc() const {
 
    return AngleLocs.getBegin();
 
  }
 
 
 
  SourceLocation getRAngleLoc() const {
 
    return AngleLocs.getEnd();
 
  }
 
};
 
 
 
/// Declaration of a redeclarable template.
 
class RedeclarableTemplateDecl : public TemplateDecl,
 
                                 public Redeclarable<RedeclarableTemplateDecl>
 
{
 
  using redeclarable_base = Redeclarable<RedeclarableTemplateDecl>;
 
 
 
  RedeclarableTemplateDecl *getNextRedeclarationImpl() override {
 
    return getNextRedeclaration();
 
  }
 
 
 
  RedeclarableTemplateDecl *getPreviousDeclImpl() override {
 
    return getPreviousDecl();
 
  }
 
 
 
  RedeclarableTemplateDecl *getMostRecentDeclImpl() override {
 
    return getMostRecentDecl();
 
  }
 
 
 
  void anchor() override;
 
protected:
 
  template <typename EntryType> struct SpecEntryTraits {
 
    using DeclType = EntryType;
 
 
 
    static DeclType *getDecl(EntryType *D) {
 
      return D;
 
    }
 
 
 
    static ArrayRef<TemplateArgument> getTemplateArgs(EntryType *D) {
 
      return D->getTemplateArgs().asArray();
 
    }
 
  };
 
 
 
  template <typename EntryType, typename SETraits = SpecEntryTraits<EntryType>,
 
            typename DeclType = typename SETraits::DeclType>
 
  struct SpecIterator
 
      : llvm::iterator_adaptor_base<
 
            SpecIterator<EntryType, SETraits, DeclType>,
 
            typename llvm::FoldingSetVector<EntryType>::iterator,
 
            typename std::iterator_traits<typename llvm::FoldingSetVector<
 
                EntryType>::iterator>::iterator_category,
 
            DeclType *, ptrdiff_t, DeclType *, DeclType *> {
 
    SpecIterator() = default;
 
    explicit SpecIterator(
 
        typename llvm::FoldingSetVector<EntryType>::iterator SetIter)
 
        : SpecIterator::iterator_adaptor_base(std::move(SetIter)) {}
 
 
 
    DeclType *operator*() const {
 
      return SETraits::getDecl(&*this->I)->getMostRecentDecl();
 
    }
 
 
 
    DeclType *operator->() const { return **this; }
 
  };
 
 
 
  template <typename EntryType>
 
  static SpecIterator<EntryType>
 
  makeSpecIterator(llvm::FoldingSetVector<EntryType> &Specs, bool isEnd) {
 
    return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
 
  }
 
 
 
  void loadLazySpecializationsImpl() const;
 
 
 
  template <class EntryType, typename ...ProfileArguments>
 
  typename SpecEntryTraits<EntryType>::DeclType*
 
  findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
 
                         void *&InsertPos, ProfileArguments &&...ProfileArgs);
 
 
 
  template <class Derived, class EntryType>
 
  void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
 
                             EntryType *Entry, void *InsertPos);
 
 
 
  struct CommonBase {
 
    CommonBase() : InstantiatedFromMember(nullptr, false) {}
 
 
 
    /// The template from which this was most
 
    /// directly instantiated (or null).
 
    ///
 
    /// The boolean value indicates whether this template
 
    /// was explicitly specialized.
 
    llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
 
      InstantiatedFromMember;
 
 
 
    /// If non-null, points to an array of specializations (including
 
    /// partial specializations) known only by their external declaration IDs.
 
    ///
 
    /// The first value in the array is the number of specializations/partial
 
    /// specializations that follow.
 
    uint32_t *LazySpecializations = nullptr;
 
 
 
    /// The set of "injected" template arguments used within this
 
    /// template.
 
    ///
 
    /// This pointer refers to the template arguments (there are as
 
    /// many template arguments as template parameaters) for the
 
    /// template, and is allocated lazily, since most templates do not
 
    /// require the use of this information.
 
    TemplateArgument *InjectedArgs = nullptr;
 
  };
 
 
 
  /// Pointer to the common data shared by all declarations of this
 
  /// template.
 
  mutable CommonBase *Common = nullptr;
 
 
 
  /// Retrieves the "common" pointer shared by all (re-)declarations of
 
  /// the same template. Calling this routine may implicitly allocate memory
 
  /// for the common pointer.
 
  CommonBase *getCommonPtr() const;
 
 
 
  virtual CommonBase *newCommon(ASTContext &C) const = 0;
 
 
 
  // Construct a template decl with name, parameters, and templated element.
 
  RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
 
                           SourceLocation L, DeclarationName Name,
 
                           TemplateParameterList *Params, NamedDecl *Decl)
 
      : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C) {}
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
  friend class ASTReader;
 
  template <class decl_type> friend class RedeclarableTemplate;
 
 
 
  /// Retrieves the canonical declaration of this template.
 
  RedeclarableTemplateDecl *getCanonicalDecl() override {
 
    return getFirstDecl();
 
  }
 
  const RedeclarableTemplateDecl *getCanonicalDecl() const {
 
    return getFirstDecl();
 
  }
 
 
 
  /// Determines whether this template was a specialization of a
 
  /// member template.
 
  ///
 
  /// In the following example, the function template \c X<int>::f and the
 
  /// member template \c X<int>::Inner are member specializations.
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// struct X {
 
  ///   template<typename U> void f(T, U);
 
  ///   template<typename U> struct Inner;
 
  /// };
 
  ///
 
  /// template<> template<typename T>
 
  /// void X<int>::f(int, T);
 
  /// template<> template<typename T>
 
  /// struct X<int>::Inner { /* ... */ };
 
  /// \endcode
 
  bool isMemberSpecialization() const {
 
    return getCommonPtr()->InstantiatedFromMember.getInt();
 
  }
 
 
 
  /// Note that this member template is a specialization.
 
  void setMemberSpecialization() {
 
    assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
 
           "Only member templates can be member template specializations");
 
    getCommonPtr()->InstantiatedFromMember.setInt(true);
 
  }
 
 
 
  /// Retrieve the member template from which this template was
 
  /// instantiated, or nullptr if this template was not instantiated from a
 
  /// member template.
 
  ///
 
  /// A template is instantiated from a member template when the member
 
  /// template itself is part of a class template (or member thereof). For
 
  /// example, given
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// struct X {
 
  ///   template<typename U> void f(T, U);
 
  /// };
 
  ///
 
  /// void test(X<int> x) {
 
  ///   x.f(1, 'a');
 
  /// };
 
  /// \endcode
 
  ///
 
  /// \c X<int>::f is a FunctionTemplateDecl that describes the function
 
  /// template
 
  ///
 
  /// \code
 
  /// template<typename U> void X<int>::f(int, U);
 
  /// \endcode
 
  ///
 
  /// which was itself created during the instantiation of \c X<int>. Calling
 
  /// getInstantiatedFromMemberTemplate() on this FunctionTemplateDecl will
 
  /// retrieve the FunctionTemplateDecl for the original template \c f within
 
  /// the class template \c X<T>, i.e.,
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// template<typename U>
 
  /// void X<T>::f(T, U);
 
  /// \endcode
 
  RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
 
    return getCommonPtr()->InstantiatedFromMember.getPointer();
 
  }
 
 
 
  void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
 
    assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
 
    getCommonPtr()->InstantiatedFromMember.setPointer(TD);
 
  }
 
 
 
  /// Retrieve the "injected" template arguments that correspond to the
 
  /// template parameters of this template.
 
  ///
 
  /// Although the C++ standard has no notion of the "injected" template
 
  /// arguments for a template, the notion is convenient when
 
  /// we need to perform substitutions inside the definition of a template.
 
  ArrayRef<TemplateArgument> getInjectedTemplateArgs();
 
 
 
  using redecl_range = redeclarable_base::redecl_range;
 
  using redecl_iterator = redeclarable_base::redecl_iterator;
 
 
 
  using redeclarable_base::redecls_begin;
 
  using redeclarable_base::redecls_end;
 
  using redeclarable_base::redecls;
 
  using redeclarable_base::getPreviousDecl;
 
  using redeclarable_base::getMostRecentDecl;
 
  using redeclarable_base::isFirstDecl;
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
 
  }
 
};
 
 
 
template <> struct RedeclarableTemplateDecl::
 
SpecEntryTraits<FunctionTemplateSpecializationInfo> {
 
  using DeclType = FunctionDecl;
 
 
 
  static DeclType *getDecl(FunctionTemplateSpecializationInfo *I) {
 
    return I->getFunction();
 
  }
 
 
 
  static ArrayRef<TemplateArgument>
 
  getTemplateArgs(FunctionTemplateSpecializationInfo *I) {
 
    return I->TemplateArguments->asArray();
 
  }
 
};
 
 
 
/// Declaration of a template function.
 
class FunctionTemplateDecl : public RedeclarableTemplateDecl {
 
protected:
 
  friend class FunctionDecl;
 
 
 
  /// Data that is common to all of the declarations of a given
 
  /// function template.
 
  struct Common : CommonBase {
 
    /// The function template specializations for this function
 
    /// template, including explicit specializations and instantiations.
 
    llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> Specializations;
 
 
 
    Common() = default;
 
  };
 
 
 
  FunctionTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
 
                       DeclarationName Name, TemplateParameterList *Params,
 
                       NamedDecl *Decl)
 
      : RedeclarableTemplateDecl(FunctionTemplate, C, DC, L, Name, Params,
 
                                 Decl) {}
 
 
 
  CommonBase *newCommon(ASTContext &C) const override;
 
 
 
  Common *getCommonPtr() const {
 
    return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
 
  }
 
 
 
  /// Retrieve the set of function template specializations of this
 
  /// function template.
 
  llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
 
  getSpecializations() const;
 
 
 
  /// Add a specialization of this function template.
 
  ///
 
  /// \param InsertPos Insert position in the FoldingSetVector, must have been
 
  ///        retrieved by an earlier call to findSpecialization().
 
  void addSpecialization(FunctionTemplateSpecializationInfo* Info,
 
                         void *InsertPos);
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  /// Load any lazily-loaded specializations from the external source.
 
  void LoadLazySpecializations() const;
 
 
 
  /// Get the underlying function declaration of the template.
 
  FunctionDecl *getTemplatedDecl() const {
 
    return static_cast<FunctionDecl *>(TemplatedDecl);
 
  }
 
 
 
  /// Returns whether this template declaration defines the primary
 
  /// pattern.
 
  bool isThisDeclarationADefinition() const {
 
    return getTemplatedDecl()->isThisDeclarationADefinition();
 
  }
 
 
 
  /// Return the specialization with the provided arguments if it exists,
 
  /// otherwise return the insertion point.
 
  FunctionDecl *findSpecialization(ArrayRef<TemplateArgument> Args,
 
                                   void *&InsertPos);
 
 
 
  FunctionTemplateDecl *getCanonicalDecl() override {
 
    return cast<FunctionTemplateDecl>(
 
             RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
  const FunctionTemplateDecl *getCanonicalDecl() const {
 
    return cast<FunctionTemplateDecl>(
 
             RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
 
 
  /// Retrieve the previous declaration of this function template, or
 
  /// nullptr if no such declaration exists.
 
  FunctionTemplateDecl *getPreviousDecl() {
 
    return cast_or_null<FunctionTemplateDecl>(
 
             static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
 
  }
 
  const FunctionTemplateDecl *getPreviousDecl() const {
 
    return cast_or_null<FunctionTemplateDecl>(
 
       static_cast<const RedeclarableTemplateDecl *>(this)->getPreviousDecl());
 
  }
 
 
 
  FunctionTemplateDecl *getMostRecentDecl() {
 
    return cast<FunctionTemplateDecl>(
 
        static_cast<RedeclarableTemplateDecl *>(this)
 
            ->getMostRecentDecl());
 
  }
 
  const FunctionTemplateDecl *getMostRecentDecl() const {
 
    return const_cast<FunctionTemplateDecl*>(this)->getMostRecentDecl();
 
  }
 
 
 
  FunctionTemplateDecl *getInstantiatedFromMemberTemplate() const {
 
    return cast_or_null<FunctionTemplateDecl>(
 
             RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
 
  }
 
 
 
  using spec_iterator = SpecIterator<FunctionTemplateSpecializationInfo>;
 
  using spec_range = llvm::iterator_range<spec_iterator>;
 
 
 
  spec_range specializations() const {
 
    return spec_range(spec_begin(), spec_end());
 
  }
 
 
 
  spec_iterator spec_begin() const {
 
    return makeSpecIterator(getSpecializations(), false);
 
  }
 
 
 
  spec_iterator spec_end() const {
 
    return makeSpecIterator(getSpecializations(), true);
 
  }
 
 
 
  /// Return whether this function template is an abbreviated function template,
 
  /// e.g. `void foo(auto x)` or `template<typename T> void foo(auto x)`
 
  bool isAbbreviated() const {
 
    // Since the invented template parameters generated from 'auto' parameters
 
    // are either appended to the end of the explicit template parameter list or
 
    // form a new template parameter list, we can simply observe the last
 
    // parameter to determine if such a thing happened.
 
    const TemplateParameterList *TPL = getTemplateParameters();
 
    return TPL->getParam(TPL->size() - 1)->isImplicit();
 
  }
 
 
 
  /// Merge \p Prev with our RedeclarableTemplateDecl::Common.
 
  void mergePrevDecl(FunctionTemplateDecl *Prev);
 
 
 
  /// Create a function template node.
 
  static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
 
                                      SourceLocation L,
 
                                      DeclarationName Name,
 
                                      TemplateParameterList *Params,
 
                                      NamedDecl *Decl);
 
 
 
  /// Create an empty function template node.
 
  static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  // Implement isa/cast/dyncast support
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == FunctionTemplate; }
 
};
 
 
 
//===----------------------------------------------------------------------===//
 
// Kinds of Template Parameters
 
//===----------------------------------------------------------------------===//
 
 
 
/// Defines the position of a template parameter within a template
 
/// parameter list.
 
///
 
/// Because template parameter can be listed
 
/// sequentially for out-of-line template members, each template parameter is
 
/// given a Depth - the nesting of template parameter scopes - and a Position -
 
/// the occurrence within the parameter list.
 
/// This class is inheritedly privately by different kinds of template
 
/// parameters and is not part of the Decl hierarchy. Just a facility.
 
class TemplateParmPosition {
 
protected:
 
  enum { DepthWidth = 20, PositionWidth = 12 };
 
  unsigned Depth : DepthWidth;
 
  unsigned Position : PositionWidth;
 
 
 
  static constexpr unsigned MaxDepth = (1U << DepthWidth) - 1;
 
  static constexpr unsigned MaxPosition = (1U << PositionWidth) - 1;
 
 
 
  TemplateParmPosition(unsigned D, unsigned P) : Depth(D), Position(P) {
 
    // The input may fill maximum values to show that it is invalid.
 
    // Add one here to convert it to zero.
 
    assert((D + 1) <= MaxDepth &&
 
           "The depth of template parmeter position is more than 2^20!");
 
    assert((P + 1) <= MaxPosition &&
 
           "The position of template parmeter position is more than 2^12!");
 
  }
 
 
 
public:
 
  TemplateParmPosition() = delete;
 
 
 
  /// Get the nesting depth of the template parameter.
 
  unsigned getDepth() const { return Depth; }
 
  void setDepth(unsigned D) {
 
    assert((D + 1) <= MaxDepth &&
 
           "The depth of template parmeter position is more than 2^20!");
 
    Depth = D;
 
  }
 
 
 
  /// Get the position of the template parameter within its parameter list.
 
  unsigned getPosition() const { return Position; }
 
  void setPosition(unsigned P) {
 
    assert((P + 1) <= MaxPosition &&
 
           "The position of template parmeter position is more than 2^12!");
 
    Position = P;
 
  }
 
 
 
  /// Get the index of the template parameter within its parameter list.
 
  unsigned getIndex() const { return Position; }
 
};
 
 
 
/// Declaration of a template type parameter.
 
///
 
/// For example, "T" in
 
/// \code
 
/// template<typename T> class vector;
 
/// \endcode
 
class TemplateTypeParmDecl final : public TypeDecl,
 
    private llvm::TrailingObjects<TemplateTypeParmDecl, TypeConstraint> {
 
  /// Sema creates these on the stack during auto type deduction.
 
  friend class Sema;
 
  friend TrailingObjects;
 
  friend class ASTDeclReader;
 
 
 
  /// Whether this template type parameter was declaration with
 
  /// the 'typename' keyword.
 
  ///
 
  /// If false, it was declared with the 'class' keyword.
 
  bool Typename : 1;
 
 
 
  /// Whether this template type parameter has a type-constraint construct.
 
  bool HasTypeConstraint : 1;
 
 
 
  /// Whether the type constraint has been initialized. This can be false if the
 
  /// constraint was not initialized yet or if there was an error forming the
 
  /// type constraint.
 
  bool TypeConstraintInitialized : 1;
 
 
 
  /// Whether this type template parameter is an "expanded"
 
  /// parameter pack, meaning that its type is a pack expansion and we
 
  /// already know the set of types that expansion expands to.
 
  bool ExpandedParameterPack : 1;
 
 
 
  /// The number of type parameters in an expanded parameter pack.
 
  unsigned NumExpanded = 0;
 
 
 
  /// The default template argument, if any.
 
  using DefArgStorage =
 
      DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *>;
 
  DefArgStorage DefaultArgument;
 
 
 
  TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc,
 
                       SourceLocation IdLoc, IdentifierInfo *Id, bool Typename,
 
                       bool HasTypeConstraint,
 
                       std::optional<unsigned> NumExpanded)
 
      : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename),
 
        HasTypeConstraint(HasTypeConstraint), TypeConstraintInitialized(false),
 
        ExpandedParameterPack(NumExpanded),
 
        NumExpanded(NumExpanded.value_or(0)) {}
 
 
 
public:
 
  static TemplateTypeParmDecl *
 
  Create(const ASTContext &C, DeclContext *DC, SourceLocation KeyLoc,
 
         SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id,
 
         bool Typename, bool ParameterPack, bool HasTypeConstraint = false,
 
         std::optional<unsigned> NumExpanded = std::nullopt);
 
  static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
 
                                                  unsigned ID);
 
  static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
 
                                                  unsigned ID,
 
                                                  bool HasTypeConstraint);
 
 
 
  /// Whether this template type parameter was declared with
 
  /// the 'typename' keyword.
 
  ///
 
  /// If not, it was either declared with the 'class' keyword or with a
 
  /// type-constraint (see hasTypeConstraint()).
 
  bool wasDeclaredWithTypename() const {
 
    return Typename && !HasTypeConstraint;
 
  }
 
 
 
  const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
 
 
 
  /// Determine whether this template parameter has a default
 
  /// argument.
 
  bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
 
 
 
  /// Retrieve the default argument, if any.
 
  QualType getDefaultArgument() const {
 
    return DefaultArgument.get()->getType();
 
  }
 
 
 
  /// Retrieves the default argument's source information, if any.
 
  TypeSourceInfo *getDefaultArgumentInfo() const {
 
    return DefaultArgument.get();
 
  }
 
 
 
  /// Retrieves the location of the default argument declaration.
 
  SourceLocation getDefaultArgumentLoc() const;
 
 
 
  /// Determines whether the default argument was inherited
 
  /// from a previous declaration of this template.
 
  bool defaultArgumentWasInherited() const {
 
    return DefaultArgument.isInherited();
 
  }
 
 
 
  /// Set the default argument for this template parameter.
 
  void setDefaultArgument(TypeSourceInfo *DefArg) {
 
    DefaultArgument.set(DefArg);
 
  }
 
 
 
  /// Set that this default argument was inherited from another
 
  /// parameter.
 
  void setInheritedDefaultArgument(const ASTContext &C,
 
                                   TemplateTypeParmDecl *Prev) {
 
    DefaultArgument.setInherited(C, Prev);
 
  }
 
 
 
  /// Removes the default argument of this template parameter.
 
  void removeDefaultArgument() {
 
    DefaultArgument.clear();
 
  }
 
 
 
  /// Set whether this template type parameter was declared with
 
  /// the 'typename' or 'class' keyword.
 
  void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; }
 
 
 
  /// Retrieve the depth of the template parameter.
 
  unsigned getDepth() const;
 
 
 
  /// Retrieve the index of the template parameter.
 
  unsigned getIndex() const;
 
 
 
  /// Returns whether this is a parameter pack.
 
  bool isParameterPack() const;
 
 
 
  /// Whether this parameter pack is a pack expansion.
 
  ///
 
  /// A template type template parameter pack can be a pack expansion if its
 
  /// type-constraint contains an unexpanded parameter pack.
 
  bool isPackExpansion() const {
 
    if (!isParameterPack())
 
      return false;
 
    if (const TypeConstraint *TC = getTypeConstraint())
 
      if (TC->hasExplicitTemplateArgs())
 
        for (const auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments())
 
          if (ArgLoc.getArgument().containsUnexpandedParameterPack())
 
            return true;
 
    return false;
 
  }
 
 
 
  /// Whether this parameter is a template type parameter pack that has a known
 
  /// list of different type-constraints at different positions.
 
  ///
 
  /// A parameter pack is an expanded parameter pack when the original
 
  /// parameter pack's type-constraint was itself a pack expansion, and that
 
  /// expansion has already been expanded. For example, given:
 
  ///
 
  /// \code
 
  /// template<typename ...Types>
 
  /// struct X {
 
  ///   template<convertible_to<Types> ...Convertibles>
 
  ///   struct Y { /* ... */ };
 
  /// };
 
  /// \endcode
 
  ///
 
  /// The parameter pack \c Convertibles has (convertible_to<Types> && ...) as
 
  /// its type-constraint. When \c Types is supplied with template arguments by
 
  /// instantiating \c X, the instantiation of \c Convertibles becomes an
 
  /// expanded parameter pack. For example, instantiating
 
  /// \c X<int, unsigned int> results in \c Convertibles being an expanded
 
  /// parameter pack of size 2 (use getNumExpansionTypes() to get this number).
 
  bool isExpandedParameterPack() const { return ExpandedParameterPack; }
 
 
 
  /// Retrieves the number of parameters in an expanded parameter pack.
 
  unsigned getNumExpansionParameters() const {
 
    assert(ExpandedParameterPack && "Not an expansion parameter pack");
 
    return NumExpanded;
 
  }
 
 
 
  /// Returns the type constraint associated with this template parameter (if
 
  /// any).
 
  const TypeConstraint *getTypeConstraint() const {
 
    return TypeConstraintInitialized ? getTrailingObjects<TypeConstraint>() :
 
         nullptr;
 
  }
 
 
 
  void setTypeConstraint(NestedNameSpecifierLoc NNS,
 
                         DeclarationNameInfo NameInfo, NamedDecl *FoundDecl,
 
                         ConceptDecl *CD,
 
                         const ASTTemplateArgumentListInfo *ArgsAsWritten,
 
                         Expr *ImmediatelyDeclaredConstraint);
 
 
 
  /// Determine whether this template parameter has a type-constraint.
 
  bool hasTypeConstraint() const {
 
    return HasTypeConstraint;
 
  }
 
 
 
  /// \brief Get the associated-constraints of this template parameter.
 
  /// This will either be the immediately-introduced constraint or empty.
 
  ///
 
  /// Use this instead of getTypeConstraint for concepts APIs that
 
  /// accept an ArrayRef of constraint expressions.
 
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
 
    if (HasTypeConstraint)
 
      AC.push_back(getTypeConstraint()->getImmediatelyDeclaredConstraint());
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY;
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == TemplateTypeParm; }
 
};
 
 
 
/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
 
/// e.g., "Size" in
 
/// @code
 
/// template<int Size> class array { };
 
/// @endcode
 
class NonTypeTemplateParmDecl final
 
    : public DeclaratorDecl,
 
      protected TemplateParmPosition,
 
      private llvm::TrailingObjects<NonTypeTemplateParmDecl,
 
                                    std::pair<QualType, TypeSourceInfo *>,
 
                                    Expr *> {
 
  friend class ASTDeclReader;
 
  friend TrailingObjects;
 
 
 
  /// The default template argument, if any, and whether or not
 
  /// it was inherited.
 
  using DefArgStorage = DefaultArgStorage<NonTypeTemplateParmDecl, Expr *>;
 
  DefArgStorage DefaultArgument;
 
 
 
  // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
 
  // down here to save memory.
 
 
 
  /// Whether this non-type template parameter is a parameter pack.
 
  bool ParameterPack;
 
 
 
  /// Whether this non-type template parameter is an "expanded"
 
  /// parameter pack, meaning that its type is a pack expansion and we
 
  /// already know the set of types that expansion expands to.
 
  bool ExpandedParameterPack = false;
 
 
 
  /// The number of types in an expanded parameter pack.
 
  unsigned NumExpandedTypes = 0;
 
 
 
  size_t numTrailingObjects(
 
      OverloadToken<std::pair<QualType, TypeSourceInfo *>>) const {
 
    return NumExpandedTypes;
 
  }
 
 
 
  NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
 
                          SourceLocation IdLoc, unsigned D, unsigned P,
 
                          IdentifierInfo *Id, QualType T,
 
                          bool ParameterPack, TypeSourceInfo *TInfo)
 
      : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
 
        TemplateParmPosition(D, P), ParameterPack(ParameterPack) {}
 
 
 
  NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
 
                          SourceLocation IdLoc, unsigned D, unsigned P,
 
                          IdentifierInfo *Id, QualType T,
 
                          TypeSourceInfo *TInfo,
 
                          ArrayRef<QualType> ExpandedTypes,
 
                          ArrayRef<TypeSourceInfo *> ExpandedTInfos);
 
 
 
public:
 
  static NonTypeTemplateParmDecl *
 
  Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
 
         SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
 
         QualType T, bool ParameterPack, TypeSourceInfo *TInfo);
 
 
 
  static NonTypeTemplateParmDecl *
 
  Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
 
         SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
 
         QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
 
         ArrayRef<TypeSourceInfo *> ExpandedTInfos);
 
 
 
  static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
 
                                                     unsigned ID,
 
                                                     bool HasTypeConstraint);
 
  static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
 
                                                     unsigned ID,
 
                                                     unsigned NumExpandedTypes,
 
                                                     bool HasTypeConstraint);
 
 
 
  using TemplateParmPosition::getDepth;
 
  using TemplateParmPosition::setDepth;
 
  using TemplateParmPosition::getPosition;
 
  using TemplateParmPosition::setPosition;
 
  using TemplateParmPosition::getIndex;
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY;
 
 
 
  const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
 
 
 
  /// Determine whether this template parameter has a default
 
  /// argument.
 
  bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
 
 
 
  /// Retrieve the default argument, if any.
 
  Expr *getDefaultArgument() const { return DefaultArgument.get(); }
 
 
 
  /// Retrieve the location of the default argument, if any.
 
  SourceLocation getDefaultArgumentLoc() const;
 
 
 
  /// Determines whether the default argument was inherited
 
  /// from a previous declaration of this template.
 
  bool defaultArgumentWasInherited() const {
 
    return DefaultArgument.isInherited();
 
  }
 
 
 
  /// Set the default argument for this template parameter, and
 
  /// whether that default argument was inherited from another
 
  /// declaration.
 
  void setDefaultArgument(Expr *DefArg) { DefaultArgument.set(DefArg); }
 
  void setInheritedDefaultArgument(const ASTContext &C,
 
                                   NonTypeTemplateParmDecl *Parm) {
 
    DefaultArgument.setInherited(C, Parm);
 
  }
 
 
 
  /// Removes the default argument of this template parameter.
 
  void removeDefaultArgument() { DefaultArgument.clear(); }
 
 
 
  /// Whether this parameter is a non-type template parameter pack.
 
  ///
 
  /// If the parameter is a parameter pack, the type may be a
 
  /// \c PackExpansionType. In the following example, the \c Dims parameter
 
  /// is a parameter pack (whose type is 'unsigned').
 
  ///
 
  /// \code
 
  /// template<typename T, unsigned ...Dims> struct multi_array;
 
  /// \endcode
 
  bool isParameterPack() const { return ParameterPack; }
 
 
 
  /// Whether this parameter pack is a pack expansion.
 
  ///
 
  /// A non-type template parameter pack is a pack expansion if its type
 
  /// contains an unexpanded parameter pack. In this case, we will have
 
  /// built a PackExpansionType wrapping the type.
 
  bool isPackExpansion() const {
 
    return ParameterPack && getType()->getAs<PackExpansionType>();
 
  }
 
 
 
  /// Whether this parameter is a non-type template parameter pack
 
  /// that has a known list of different types at different positions.
 
  ///
 
  /// A parameter pack is an expanded parameter pack when the original
 
  /// parameter pack's type was itself a pack expansion, and that expansion
 
  /// has already been expanded. For example, given:
 
  ///
 
  /// \code
 
  /// template<typename ...Types>
 
  /// struct X {
 
  ///   template<Types ...Values>
 
  ///   struct Y { /* ... */ };
 
  /// };
 
  /// \endcode
 
  ///
 
  /// The parameter pack \c Values has a \c PackExpansionType as its type,
 
  /// which expands \c Types. When \c Types is supplied with template arguments
 
  /// by instantiating \c X, the instantiation of \c Values becomes an
 
  /// expanded parameter pack. For example, instantiating
 
  /// \c X<int, unsigned int> results in \c Values being an expanded parameter
 
  /// pack with expansion types \c int and \c unsigned int.
 
  ///
 
  /// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions
 
  /// return the expansion types.
 
  bool isExpandedParameterPack() const { return ExpandedParameterPack; }
 
 
 
  /// Retrieves the number of expansion types in an expanded parameter
 
  /// pack.
 
  unsigned getNumExpansionTypes() const {
 
    assert(ExpandedParameterPack && "Not an expansion parameter pack");
 
    return NumExpandedTypes;
 
  }
 
 
 
  /// Retrieve a particular expansion type within an expanded parameter
 
  /// pack.
 
  QualType getExpansionType(unsigned I) const {
 
    assert(I < NumExpandedTypes && "Out-of-range expansion type index");
 
    auto TypesAndInfos =
 
        getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
 
    return TypesAndInfos[I].first;
 
  }
 
 
 
  /// Retrieve a particular expansion type source info within an
 
  /// expanded parameter pack.
 
  TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const {
 
    assert(I < NumExpandedTypes && "Out-of-range expansion type index");
 
    auto TypesAndInfos =
 
        getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
 
    return TypesAndInfos[I].second;
 
  }
 
 
 
  /// Return the constraint introduced by the placeholder type of this non-type
 
  /// template parameter (if any).
 
  Expr *getPlaceholderTypeConstraint() const {
 
    return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() :
 
        nullptr;
 
  }
 
 
 
  void setPlaceholderTypeConstraint(Expr *E) {
 
    *getTrailingObjects<Expr *>() = E;
 
  }
 
 
 
  /// Determine whether this non-type template parameter's type has a
 
  /// placeholder with a type-constraint.
 
  bool hasPlaceholderTypeConstraint() const {
 
    auto *AT = getType()->getContainedAutoType();
 
    return AT && AT->isConstrained();
 
  }
 
 
 
  /// \brief Get the associated-constraints of this template parameter.
 
  /// This will either be a vector of size 1 containing the immediately-declared
 
  /// constraint introduced by the placeholder type, or an empty vector.
 
  ///
 
  /// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
 
  /// concepts APIs that accept an ArrayRef of constraint expressions.
 
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
 
    if (Expr *E = getPlaceholderTypeConstraint())
 
      AC.push_back(E);
 
  }
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
 
};
 
 
 
/// TemplateTemplateParmDecl - Declares a template template parameter,
 
/// e.g., "T" in
 
/// @code
 
/// template <template <typename> class T> class container { };
 
/// @endcode
 
/// A template template parameter is a TemplateDecl because it defines the
 
/// name of a template and the template parameters allowable for substitution.
 
class TemplateTemplateParmDecl final
 
    : public TemplateDecl,
 
      protected TemplateParmPosition,
 
      private llvm::TrailingObjects<TemplateTemplateParmDecl,
 
                                    TemplateParameterList *> {
 
  /// The default template argument, if any.
 
  using DefArgStorage =
 
      DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>;
 
  DefArgStorage DefaultArgument;
 
 
 
  /// Whether this parameter is a parameter pack.
 
  bool ParameterPack;
 
 
 
  /// Whether this template template parameter is an "expanded"
 
  /// parameter pack, meaning that it is a pack expansion and we
 
  /// already know the set of template parameters that expansion expands to.
 
  bool ExpandedParameterPack = false;
 
 
 
  /// The number of parameters in an expanded parameter pack.
 
  unsigned NumExpandedParams = 0;
 
 
 
  TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
 
                           unsigned D, unsigned P, bool ParameterPack,
 
                           IdentifierInfo *Id, TemplateParameterList *Params)
 
      : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
 
        TemplateParmPosition(D, P), ParameterPack(ParameterPack) {}
 
 
 
  TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
 
                           unsigned D, unsigned P,
 
                           IdentifierInfo *Id, TemplateParameterList *Params,
 
                           ArrayRef<TemplateParameterList *> Expansions);
 
 
 
  void anchor() override;
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
  friend TrailingObjects;
 
 
 
  static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
 
                                          SourceLocation L, unsigned D,
 
                                          unsigned P, bool ParameterPack,
 
                                          IdentifierInfo *Id,
 
                                          TemplateParameterList *Params);
 
  static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
 
                                          SourceLocation L, unsigned D,
 
                                          unsigned P,
 
                                          IdentifierInfo *Id,
 
                                          TemplateParameterList *Params,
 
                                 ArrayRef<TemplateParameterList *> Expansions);
 
 
 
  static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
 
                                                      unsigned ID);
 
  static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
 
                                                      unsigned ID,
 
                                                      unsigned NumExpansions);
 
 
 
  using TemplateParmPosition::getDepth;
 
  using TemplateParmPosition::setDepth;
 
  using TemplateParmPosition::getPosition;
 
  using TemplateParmPosition::setPosition;
 
  using TemplateParmPosition::getIndex;
 
 
 
  /// Whether this template template parameter is a template
 
  /// parameter pack.
 
  ///
 
  /// \code
 
  /// template<template <class T> ...MetaFunctions> struct Apply;
 
  /// \endcode
 
  bool isParameterPack() const { return ParameterPack; }
 
 
 
  /// Whether this parameter pack is a pack expansion.
 
  ///
 
  /// A template template parameter pack is a pack expansion if its template
 
  /// parameter list contains an unexpanded parameter pack.
 
  bool isPackExpansion() const {
 
    return ParameterPack &&
 
           getTemplateParameters()->containsUnexpandedParameterPack();
 
  }
 
 
 
  /// Whether this parameter is a template template parameter pack that
 
  /// has a known list of different template parameter lists at different
 
  /// positions.
 
  ///
 
  /// A parameter pack is an expanded parameter pack when the original parameter
 
  /// pack's template parameter list was itself a pack expansion, and that
 
  /// expansion has already been expanded. For exampe, given:
 
  ///
 
  /// \code
 
  /// template<typename...Types> struct Outer {
 
  ///   template<template<Types> class...Templates> struct Inner;
 
  /// };
 
  /// \endcode
 
  ///
 
  /// The parameter pack \c Templates is a pack expansion, which expands the
 
  /// pack \c Types. When \c Types is supplied with template arguments by
 
  /// instantiating \c Outer, the instantiation of \c Templates is an expanded
 
  /// parameter pack.
 
  bool isExpandedParameterPack() const { return ExpandedParameterPack; }
 
 
 
  /// Retrieves the number of expansion template parameters in
 
  /// an expanded parameter pack.
 
  unsigned getNumExpansionTemplateParameters() const {
 
    assert(ExpandedParameterPack && "Not an expansion parameter pack");
 
    return NumExpandedParams;
 
  }
 
 
 
  /// Retrieve a particular expansion type within an expanded parameter
 
  /// pack.
 
  TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
 
    assert(I < NumExpandedParams && "Out-of-range expansion type index");
 
    return getTrailingObjects<TemplateParameterList *>()[I];
 
  }
 
 
 
  const DefArgStorage &getDefaultArgStorage() const { return DefaultArgument; }
 
 
 
  /// Determine whether this template parameter has a default
 
  /// argument.
 
  bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
 
 
 
  /// Retrieve the default argument, if any.
 
  const TemplateArgumentLoc &getDefaultArgument() const {
 
    static const TemplateArgumentLoc NoneLoc;
 
    return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc;
 
  }
 
 
 
  /// Retrieve the location of the default argument, if any.
 
  SourceLocation getDefaultArgumentLoc() const;
 
 
 
  /// Determines whether the default argument was inherited
 
  /// from a previous declaration of this template.
 
  bool defaultArgumentWasInherited() const {
 
    return DefaultArgument.isInherited();
 
  }
 
 
 
  /// Set the default argument for this template parameter, and
 
  /// whether that default argument was inherited from another
 
  /// declaration.
 
  void setDefaultArgument(const ASTContext &C,
 
                          const TemplateArgumentLoc &DefArg);
 
  void setInheritedDefaultArgument(const ASTContext &C,
 
                                   TemplateTemplateParmDecl *Prev) {
 
    DefaultArgument.setInherited(C, Prev);
 
  }
 
 
 
  /// Removes the default argument of this template parameter.
 
  void removeDefaultArgument() { DefaultArgument.clear(); }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY {
 
    SourceLocation End = getLocation();
 
    if (hasDefaultArgument() && !defaultArgumentWasInherited())
 
      End = getDefaultArgument().getSourceRange().getEnd();
 
    return SourceRange(getTemplateParameters()->getTemplateLoc(), End);
 
  }
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
 
};
 
 
 
/// Represents the builtin template declaration which is used to
 
/// implement __make_integer_seq and other builtin templates.  It serves
 
/// no real purpose beyond existing as a place to hold template parameters.
 
class BuiltinTemplateDecl : public TemplateDecl {
 
  BuiltinTemplateKind BTK;
 
 
 
  BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
 
                      DeclarationName Name, BuiltinTemplateKind BTK);
 
 
 
  void anchor() override;
 
 
 
public:
 
  // Implement isa/cast/dyncast support
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == BuiltinTemplate; }
 
 
 
  static BuiltinTemplateDecl *Create(const ASTContext &C, DeclContext *DC,
 
                                     DeclarationName Name,
 
                                     BuiltinTemplateKind BTK) {
 
    return new (C, DC) BuiltinTemplateDecl(C, DC, Name, BTK);
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY {
 
    return {};
 
  }
 
 
 
  BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
 
};
 
 
 
/// Represents a class template specialization, which refers to
 
/// a class template with a given set of template arguments.
 
///
 
/// Class template specializations represent both explicit
 
/// specialization of class templates, as in the example below, and
 
/// implicit instantiations of class templates.
 
///
 
/// \code
 
/// template<typename T> class array;
 
///
 
/// template<>
 
/// class array<bool> { }; // class template specialization array<bool>
 
/// \endcode
 
class ClassTemplateSpecializationDecl
 
  : public CXXRecordDecl, public llvm::FoldingSetNode {
 
  /// Structure that stores information about a class template
 
  /// specialization that was instantiated from a class template partial
 
  /// specialization.
 
  struct SpecializedPartialSpecialization {
 
    /// The class template partial specialization from which this
 
    /// class template specialization was instantiated.
 
    ClassTemplatePartialSpecializationDecl *PartialSpecialization;
 
 
 
    /// The template argument list deduced for the class template
 
    /// partial specialization itself.
 
    const TemplateArgumentList *TemplateArgs;
 
  };
 
 
 
  /// The template that this specialization specializes
 
  llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *>
 
    SpecializedTemplate;
 
 
 
  /// Further info for explicit template specialization/instantiation.
 
  struct ExplicitSpecializationInfo {
 
    /// The type-as-written.
 
    TypeSourceInfo *TypeAsWritten = nullptr;
 
 
 
    /// The location of the extern keyword.
 
    SourceLocation ExternLoc;
 
 
 
    /// The location of the template keyword.
 
    SourceLocation TemplateKeywordLoc;
 
 
 
    ExplicitSpecializationInfo() = default;
 
  };
 
 
 
  /// Further info for explicit template specialization/instantiation.
 
  /// Does not apply to implicit specializations.
 
  ExplicitSpecializationInfo *ExplicitInfo = nullptr;
 
 
 
  /// The template arguments used to describe this specialization.
 
  const TemplateArgumentList *TemplateArgs;
 
 
 
  /// The point where this template was instantiated (if any)
 
  SourceLocation PointOfInstantiation;
 
 
 
  /// The kind of specialization this declaration refers to.
 
  /// Really a value of type TemplateSpecializationKind.
 
  unsigned SpecializationKind : 3;
 
 
 
protected:
 
  ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
 
                                  DeclContext *DC, SourceLocation StartLoc,
 
                                  SourceLocation IdLoc,
 
                                  ClassTemplateDecl *SpecializedTemplate,
 
                                  ArrayRef<TemplateArgument> Args,
 
                                  ClassTemplateSpecializationDecl *PrevDecl);
 
 
 
  explicit ClassTemplateSpecializationDecl(ASTContext &C, Kind DK);
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  static ClassTemplateSpecializationDecl *
 
  Create(ASTContext &Context, TagKind TK, DeclContext *DC,
 
         SourceLocation StartLoc, SourceLocation IdLoc,
 
         ClassTemplateDecl *SpecializedTemplate,
 
         ArrayRef<TemplateArgument> Args,
 
         ClassTemplateSpecializationDecl *PrevDecl);
 
  static ClassTemplateSpecializationDecl *
 
  CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
 
                            bool Qualified) const override;
 
 
 
  // FIXME: This is broken. CXXRecordDecl::getMostRecentDecl() returns a
 
  // different "most recent" declaration from this function for the same
 
  // declaration, because we don't override getMostRecentDeclImpl(). But
 
  // it's not clear that we should override that, because the most recent
 
  // declaration as a CXXRecordDecl sometimes is the injected-class-name.
 
  ClassTemplateSpecializationDecl *getMostRecentDecl() {
 
    return cast<ClassTemplateSpecializationDecl>(
 
        getMostRecentNonInjectedDecl());
 
  }
 
 
 
  /// Retrieve the template that this specialization specializes.
 
  ClassTemplateDecl *getSpecializedTemplate() const;
 
 
 
  /// Retrieve the template arguments of the class template
 
  /// specialization.
 
  const TemplateArgumentList &getTemplateArgs() const {
 
    return *TemplateArgs;
 
  }
 
 
 
  void setTemplateArgs(TemplateArgumentList *Args) {
 
    TemplateArgs = Args;
 
  }
 
 
 
  /// Determine the kind of specialization that this
 
  /// declaration represents.
 
  TemplateSpecializationKind getSpecializationKind() const {
 
    return static_cast<TemplateSpecializationKind>(SpecializationKind);
 
  }
 
 
 
  bool isExplicitSpecialization() const {
 
    return getSpecializationKind() == TSK_ExplicitSpecialization;
 
  }
 
 
 
  /// Is this an explicit specialization at class scope (within the class that
 
  /// owns the primary template)? For example:
 
  ///
 
  /// \code
 
  /// template<typename T> struct Outer {
 
  ///   template<typename U> struct Inner;
 
  ///   template<> struct Inner; // class-scope explicit specialization
 
  /// };
 
  /// \endcode
 
  bool isClassScopeExplicitSpecialization() const {
 
    return isExplicitSpecialization() &&
 
           isa<CXXRecordDecl>(getLexicalDeclContext());
 
  }
 
 
 
  /// True if this declaration is an explicit specialization,
 
  /// explicit instantiation declaration, or explicit instantiation
 
  /// definition.
 
  bool isExplicitInstantiationOrSpecialization() const {
 
    return isTemplateExplicitInstantiationOrSpecialization(
 
        getTemplateSpecializationKind());
 
  }
 
 
 
  void setSpecializedTemplate(ClassTemplateDecl *Specialized) {
 
    SpecializedTemplate = Specialized;
 
  }
 
 
 
  void setSpecializationKind(TemplateSpecializationKind TSK) {
 
    SpecializationKind = TSK;
 
  }
 
 
 
  /// Get the point of instantiation (if any), or null if none.
 
  SourceLocation getPointOfInstantiation() const {
 
    return PointOfInstantiation;
 
  }
 
 
 
  void setPointOfInstantiation(SourceLocation Loc) {
 
    assert(Loc.isValid() && "point of instantiation must be valid!");
 
    PointOfInstantiation = Loc;
 
  }
 
 
 
  /// If this class template specialization is an instantiation of
 
  /// a template (rather than an explicit specialization), return the
 
  /// class template or class template partial specialization from which it
 
  /// was instantiated.
 
  llvm::PointerUnion<ClassTemplateDecl *,
 
                     ClassTemplatePartialSpecializationDecl *>
 
  getInstantiatedFrom() const {
 
    if (!isTemplateInstantiation(getSpecializationKind()))
 
      return llvm::PointerUnion<ClassTemplateDecl *,
 
                                ClassTemplatePartialSpecializationDecl *>();
 
 
 
    return getSpecializedTemplateOrPartial();
 
  }
 
 
 
  /// Retrieve the class template or class template partial
 
  /// specialization which was specialized by this.
 
  llvm::PointerUnion<ClassTemplateDecl *,
 
                     ClassTemplatePartialSpecializationDecl *>
 
  getSpecializedTemplateOrPartial() const {
 
    if (const auto *PartialSpec =
 
            SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
 
      return PartialSpec->PartialSpecialization;
 
 
 
    return SpecializedTemplate.get<ClassTemplateDecl*>();
 
  }
 
 
 
  /// Retrieve the set of template arguments that should be used
 
  /// to instantiate members of the class template or class template partial
 
  /// specialization from which this class template specialization was
 
  /// instantiated.
 
  ///
 
  /// \returns For a class template specialization instantiated from the primary
 
  /// template, this function will return the same template arguments as
 
  /// getTemplateArgs(). For a class template specialization instantiated from
 
  /// a class template partial specialization, this function will return the
 
  /// deduced template arguments for the class template partial specialization
 
  /// itself.
 
  const TemplateArgumentList &getTemplateInstantiationArgs() const {
 
    if (const auto *PartialSpec =
 
            SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
 
      return *PartialSpec->TemplateArgs;
 
 
 
    return getTemplateArgs();
 
  }
 
 
 
  /// Note that this class template specialization is actually an
 
  /// instantiation of the given class template partial specialization whose
 
  /// template arguments have been deduced.
 
  void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
 
                          const TemplateArgumentList *TemplateArgs) {
 
    assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
 
           "Already set to a class template partial specialization!");
 
    auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
 
    PS->PartialSpecialization = PartialSpec;
 
    PS->TemplateArgs = TemplateArgs;
 
    SpecializedTemplate = PS;
 
  }
 
 
 
  /// Note that this class template specialization is an instantiation
 
  /// of the given class template.
 
  void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
 
    assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
 
           "Previously set to a class template partial specialization!");
 
    SpecializedTemplate = TemplDecl;
 
  }
 
 
 
  /// Sets the type of this specialization as it was written by
 
  /// the user. This will be a class template specialization type.
 
  void setTypeAsWritten(TypeSourceInfo *T) {
 
    if (!ExplicitInfo)
 
      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
 
    ExplicitInfo->TypeAsWritten = T;
 
  }
 
 
 
  /// Gets the type of this specialization as it was written by
 
  /// the user, if it was so written.
 
  TypeSourceInfo *getTypeAsWritten() const {
 
    return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
 
  }
 
 
 
  /// Gets the location of the extern keyword, if present.
 
  SourceLocation getExternLoc() const {
 
    return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
 
  }
 
 
 
  /// Sets the location of the extern keyword.
 
  void setExternLoc(SourceLocation Loc) {
 
    if (!ExplicitInfo)
 
      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
 
    ExplicitInfo->ExternLoc = Loc;
 
  }
 
 
 
  /// Sets the location of the template keyword.
 
  void setTemplateKeywordLoc(SourceLocation Loc) {
 
    if (!ExplicitInfo)
 
      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
 
    ExplicitInfo->TemplateKeywordLoc = Loc;
 
  }
 
 
 
  /// Gets the location of the template keyword, if present.
 
  SourceLocation getTemplateKeywordLoc() const {
 
    return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY;
 
 
 
  void Profile(llvm::FoldingSetNodeID &ID) const {
 
    Profile(ID, TemplateArgs->asArray(), getASTContext());
 
  }
 
 
 
  static void
 
  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
 
          ASTContext &Context) {
 
    ID.AddInteger(TemplateArgs.size());
 
    for (const TemplateArgument &TemplateArg : TemplateArgs)
 
      TemplateArg.Profile(ID, Context);
 
  }
 
 
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K >= firstClassTemplateSpecialization &&
 
           K <= lastClassTemplateSpecialization;
 
  }
 
};
 
 
 
class ClassTemplatePartialSpecializationDecl
 
  : public ClassTemplateSpecializationDecl {
 
  /// The list of template parameters
 
  TemplateParameterList* TemplateParams = nullptr;
 
 
 
  /// The source info for the template arguments as written.
 
  /// FIXME: redundant with TypeAsWritten?
 
  const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
 
 
 
  /// The class template partial specialization from which this
 
  /// class template partial specialization was instantiated.
 
  ///
 
  /// The boolean value will be true to indicate that this class template
 
  /// partial specialization was specialized at this level.
 
  llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
 
      InstantiatedFromMember;
 
 
 
  ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
 
                                         DeclContext *DC,
 
                                         SourceLocation StartLoc,
 
                                         SourceLocation IdLoc,
 
                                         TemplateParameterList *Params,
 
                                         ClassTemplateDecl *SpecializedTemplate,
 
                                         ArrayRef<TemplateArgument> Args,
 
                               const ASTTemplateArgumentListInfo *ArgsAsWritten,
 
                               ClassTemplatePartialSpecializationDecl *PrevDecl);
 
 
 
  ClassTemplatePartialSpecializationDecl(ASTContext &C)
 
    : ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization),
 
      InstantiatedFromMember(nullptr, false) {}
 
 
 
  void anchor() override;
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  static ClassTemplatePartialSpecializationDecl *
 
  Create(ASTContext &Context, TagKind TK, DeclContext *DC,
 
         SourceLocation StartLoc, SourceLocation IdLoc,
 
         TemplateParameterList *Params,
 
         ClassTemplateDecl *SpecializedTemplate,
 
         ArrayRef<TemplateArgument> Args,
 
         const TemplateArgumentListInfo &ArgInfos,
 
         QualType CanonInjectedType,
 
         ClassTemplatePartialSpecializationDecl *PrevDecl);
 
 
 
  static ClassTemplatePartialSpecializationDecl *
 
  CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
 
    return cast<ClassTemplatePartialSpecializationDecl>(
 
             static_cast<ClassTemplateSpecializationDecl *>(
 
               this)->getMostRecentDecl());
 
  }
 
 
 
  /// Get the list of template parameters
 
  TemplateParameterList *getTemplateParameters() const {
 
    return TemplateParams;
 
  }
 
 
 
  /// \brief All associated constraints of this partial specialization,
 
  /// including the requires clause and any constraints derived from
 
  /// constrained-parameters.
 
  ///
 
  /// The constraints in the resulting list are to be treated as if in a
 
  /// conjunction ("and").
 
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
 
    TemplateParams->getAssociatedConstraints(AC);
 
  }
 
 
 
  bool hasAssociatedConstraints() const {
 
    return TemplateParams->hasAssociatedConstraints();
 
  }
 
 
 
  /// Get the template arguments as written.
 
  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
 
    return ArgsAsWritten;
 
  }
 
 
 
  /// Retrieve the member class template partial specialization from
 
  /// which this particular class template partial specialization was
 
  /// instantiated.
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// struct Outer {
 
  ///   template<typename U> struct Inner;
 
  ///   template<typename U> struct Inner<U*> { }; // #1
 
  /// };
 
  ///
 
  /// Outer<float>::Inner<int*> ii;
 
  /// \endcode
 
  ///
 
  /// In this example, the instantiation of \c Outer<float>::Inner<int*> will
 
  /// end up instantiating the partial specialization
 
  /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class
 
  /// template partial specialization \c Outer<T>::Inner<U*>. Given
 
  /// \c Outer<float>::Inner<U*>, this function would return
 
  /// \c Outer<T>::Inner<U*>.
 
  ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() const {
 
    const auto *First =
 
        cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
 
    return First->InstantiatedFromMember.getPointer();
 
  }
 
  ClassTemplatePartialSpecializationDecl *
 
  getInstantiatedFromMemberTemplate() const {
 
    return getInstantiatedFromMember();
 
  }
 
 
 
  void setInstantiatedFromMember(
 
                          ClassTemplatePartialSpecializationDecl *PartialSpec) {
 
    auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
 
    First->InstantiatedFromMember.setPointer(PartialSpec);
 
  }
 
 
 
  /// Determines whether this class template partial specialization
 
  /// template was a specialization of a member partial specialization.
 
  ///
 
  /// In the following example, the member template partial specialization
 
  /// \c X<int>::Inner<T*> is a member specialization.
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// struct X {
 
  ///   template<typename U> struct Inner;
 
  ///   template<typename U> struct Inner<U*>;
 
  /// };
 
  ///
 
  /// template<> template<typename T>
 
  /// struct X<int>::Inner<T*> { /* ... */ };
 
  /// \endcode
 
  bool isMemberSpecialization() {
 
    const auto *First =
 
        cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
 
    return First->InstantiatedFromMember.getInt();
 
  }
 
 
 
  /// Note that this member template is a specialization.
 
  void setMemberSpecialization() {
 
    auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
 
    assert(First->InstantiatedFromMember.getPointer() &&
 
           "Only member templates can be member template specializations");
 
    return First->InstantiatedFromMember.setInt(true);
 
  }
 
 
 
  /// Retrieves the injected specialization type for this partial
 
  /// specialization.  This is not the same as the type-decl-type for
 
  /// this partial specialization, which is an InjectedClassNameType.
 
  QualType getInjectedSpecializationType() const {
 
    assert(getTypeForDecl() && "partial specialization has no type set!");
 
    return cast<InjectedClassNameType>(getTypeForDecl())
 
             ->getInjectedSpecializationType();
 
  }
 
 
 
  void Profile(llvm::FoldingSetNodeID &ID) const {
 
    Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
 
            getASTContext());
 
  }
 
 
 
  static void
 
  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
 
          TemplateParameterList *TPL, ASTContext &Context);
 
 
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K == ClassTemplatePartialSpecialization;
 
  }
 
};
 
 
 
/// Declaration of a class template.
 
class ClassTemplateDecl : public RedeclarableTemplateDecl {
 
protected:
 
  /// Data that is common to all of the declarations of a given
 
  /// class template.
 
  struct Common : CommonBase {
 
    /// The class template specializations for this class
 
    /// template, including explicit specializations and instantiations.
 
    llvm::FoldingSetVector<ClassTemplateSpecializationDecl> Specializations;
 
 
 
    /// The class template partial specializations for this class
 
    /// template.
 
    llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>
 
      PartialSpecializations;
 
 
 
    /// The injected-class-name type for this class template.
 
    QualType InjectedClassNameType;
 
 
 
    Common() = default;
 
  };
 
 
 
  /// Retrieve the set of specializations of this class template.
 
  llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
 
  getSpecializations() const;
 
 
 
  /// Retrieve the set of partial specializations of this class
 
  /// template.
 
  llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
 
  getPartialSpecializations() const;
 
 
 
  ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
 
                    DeclarationName Name, TemplateParameterList *Params,
 
                    NamedDecl *Decl)
 
      : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
 
 
 
  CommonBase *newCommon(ASTContext &C) const override;
 
 
 
  Common *getCommonPtr() const {
 
    return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
 
  }
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  /// Load any lazily-loaded specializations from the external source.
 
  void LoadLazySpecializations() const;
 
 
 
  /// Get the underlying class declarations of the template.
 
  CXXRecordDecl *getTemplatedDecl() const {
 
    return static_cast<CXXRecordDecl *>(TemplatedDecl);
 
  }
 
 
 
  /// Returns whether this template declaration defines the primary
 
  /// class pattern.
 
  bool isThisDeclarationADefinition() const {
 
    return getTemplatedDecl()->isThisDeclarationADefinition();
 
  }
 
 
 
  /// \brief Create a class template node.
 
  static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
 
                                   SourceLocation L,
 
                                   DeclarationName Name,
 
                                   TemplateParameterList *Params,
 
                                   NamedDecl *Decl);
 
 
 
  /// Create an empty class template node.
 
  static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  /// Return the specialization with the provided arguments if it exists,
 
  /// otherwise return the insertion point.
 
  ClassTemplateSpecializationDecl *
 
  findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos);
 
 
 
  /// Insert the specified specialization knowing that it is not already
 
  /// in. InsertPos must be obtained from findSpecialization.
 
  void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos);
 
 
 
  ClassTemplateDecl *getCanonicalDecl() override {
 
    return cast<ClassTemplateDecl>(
 
             RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
  const ClassTemplateDecl *getCanonicalDecl() const {
 
    return cast<ClassTemplateDecl>(
 
             RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
 
 
  /// Retrieve the previous declaration of this class template, or
 
  /// nullptr if no such declaration exists.
 
  ClassTemplateDecl *getPreviousDecl() {
 
    return cast_or_null<ClassTemplateDecl>(
 
             static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
 
  }
 
  const ClassTemplateDecl *getPreviousDecl() const {
 
    return cast_or_null<ClassTemplateDecl>(
 
             static_cast<const RedeclarableTemplateDecl *>(
 
               this)->getPreviousDecl());
 
  }
 
 
 
  ClassTemplateDecl *getMostRecentDecl() {
 
    return cast<ClassTemplateDecl>(
 
        static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
 
  }
 
  const ClassTemplateDecl *getMostRecentDecl() const {
 
    return const_cast<ClassTemplateDecl*>(this)->getMostRecentDecl();
 
  }
 
 
 
  ClassTemplateDecl *getInstantiatedFromMemberTemplate() const {
 
    return cast_or_null<ClassTemplateDecl>(
 
             RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
 
  }
 
 
 
  /// Return the partial specialization with the provided arguments if it
 
  /// exists, otherwise return the insertion point.
 
  ClassTemplatePartialSpecializationDecl *
 
  findPartialSpecialization(ArrayRef<TemplateArgument> Args,
 
                            TemplateParameterList *TPL, void *&InsertPos);
 
 
 
  /// Insert the specified partial specialization knowing that it is not
 
  /// already in. InsertPos must be obtained from findPartialSpecialization.
 
  void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D,
 
                                void *InsertPos);
 
 
 
  /// Retrieve the partial specializations as an ordered list.
 
  void getPartialSpecializations(
 
      SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) const;
 
 
 
  /// Find a class template partial specialization with the given
 
  /// type T.
 
  ///
 
  /// \param T a dependent type that names a specialization of this class
 
  /// template.
 
  ///
 
  /// \returns the class template partial specialization that exactly matches
 
  /// the type \p T, or nullptr if no such partial specialization exists.
 
  ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T);
 
 
 
  /// Find a class template partial specialization which was instantiated
 
  /// from the given member partial specialization.
 
  ///
 
  /// \param D a member class template partial specialization.
 
  ///
 
  /// \returns the class template partial specialization which was instantiated
 
  /// from the given member partial specialization, or nullptr if no such
 
  /// partial specialization exists.
 
  ClassTemplatePartialSpecializationDecl *
 
  findPartialSpecInstantiatedFromMember(
 
                                     ClassTemplatePartialSpecializationDecl *D);
 
 
 
  /// Retrieve the template specialization type of the
 
  /// injected-class-name for this class template.
 
  ///
 
  /// The injected-class-name for a class template \c X is \c
 
  /// X<template-args>, where \c template-args is formed from the
 
  /// template arguments that correspond to the template parameters of
 
  /// \c X. For example:
 
  ///
 
  /// \code
 
  /// template<typename T, int N>
 
  /// struct array {
 
  ///   typedef array this_type; // "array" is equivalent to "array<T, N>"
 
  /// };
 
  /// \endcode
 
  QualType getInjectedClassNameSpecialization();
 
 
 
  using spec_iterator = SpecIterator<ClassTemplateSpecializationDecl>;
 
  using spec_range = llvm::iterator_range<spec_iterator>;
 
 
 
  spec_range specializations() const {
 
    return spec_range(spec_begin(), spec_end());
 
  }
 
 
 
  spec_iterator spec_begin() const {
 
    return makeSpecIterator(getSpecializations(), false);
 
  }
 
 
 
  spec_iterator spec_end() const {
 
    return makeSpecIterator(getSpecializations(), true);
 
  }
 
 
 
  // Implement isa/cast/dyncast support
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == ClassTemplate; }
 
};
 
 
 
/// Declaration of a friend template.
 
///
 
/// For example:
 
/// \code
 
/// template \<typename T> class A {
 
///   friend class MyVector<T>; // not a friend template
 
///   template \<typename U> friend class B; // not a friend template
 
///   template \<typename U> friend class Foo<T>::Nested; // friend template
 
/// };
 
/// \endcode
 
///
 
/// \note This class is not currently in use.  All of the above
 
/// will yield a FriendDecl, not a FriendTemplateDecl.
 
class FriendTemplateDecl : public Decl {
 
  virtual void anchor();
 
 
 
public:
 
  using FriendUnion = llvm::PointerUnion<NamedDecl *,TypeSourceInfo *>;
 
 
 
private:
 
  // The number of template parameters;  always non-zero.
 
  unsigned NumParams = 0;
 
 
 
  // The parameter list.
 
  TemplateParameterList **Params = nullptr;
 
 
 
  // The declaration that's a friend of this class.
 
  FriendUnion Friend;
 
 
 
  // Location of the 'friend' specifier.
 
  SourceLocation FriendLoc;
 
 
 
  FriendTemplateDecl(DeclContext *DC, SourceLocation Loc,
 
                     TemplateParameterList **Params, unsigned NumParams,
 
                     FriendUnion Friend, SourceLocation FriendLoc)
 
      : Decl(Decl::FriendTemplate, DC, Loc), NumParams(NumParams),
 
        Params(Params), Friend(Friend), FriendLoc(FriendLoc) {}
 
 
 
  FriendTemplateDecl(EmptyShell Empty) : Decl(Decl::FriendTemplate, Empty) {}
 
 
 
public:
 
  friend class ASTDeclReader;
 
 
 
  static FriendTemplateDecl *
 
  Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc,
 
         MutableArrayRef<TemplateParameterList *> Params, FriendUnion Friend,
 
         SourceLocation FriendLoc);
 
 
 
  static FriendTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  /// If this friend declaration names a templated type (or
 
  /// a dependent member type of a templated type), return that
 
  /// type;  otherwise return null.
 
  TypeSourceInfo *getFriendType() const {
 
    return Friend.dyn_cast<TypeSourceInfo*>();
 
  }
 
 
 
  /// If this friend declaration names a templated function (or
 
  /// a member function of a templated type), return that type;
 
  /// otherwise return null.
 
  NamedDecl *getFriendDecl() const {
 
    return Friend.dyn_cast<NamedDecl*>();
 
  }
 
 
 
  /// Retrieves the location of the 'friend' keyword.
 
  SourceLocation getFriendLoc() const {
 
    return FriendLoc;
 
  }
 
 
 
  TemplateParameterList *getTemplateParameterList(unsigned i) const {
 
    assert(i <= NumParams);
 
    return Params[i];
 
  }
 
 
 
  unsigned getNumTemplateParameters() const {
 
    return NumParams;
 
  }
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == Decl::FriendTemplate; }
 
};
 
 
 
/// Declaration of an alias template.
 
///
 
/// For example:
 
/// \code
 
/// template \<typename T> using V = std::map<T*, int, MyCompare<T>>;
 
/// \endcode
 
class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
 
protected:
 
  using Common = CommonBase;
 
 
 
  TypeAliasTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
 
                        DeclarationName Name, TemplateParameterList *Params,
 
                        NamedDecl *Decl)
 
      : RedeclarableTemplateDecl(TypeAliasTemplate, C, DC, L, Name, Params,
 
                                 Decl) {}
 
 
 
  CommonBase *newCommon(ASTContext &C) const override;
 
 
 
  Common *getCommonPtr() {
 
    return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
 
  }
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  /// Get the underlying function declaration of the template.
 
  TypeAliasDecl *getTemplatedDecl() const {
 
    return static_cast<TypeAliasDecl *>(TemplatedDecl);
 
  }
 
 
 
 
 
  TypeAliasTemplateDecl *getCanonicalDecl() override {
 
    return cast<TypeAliasTemplateDecl>(
 
             RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
  const TypeAliasTemplateDecl *getCanonicalDecl() const {
 
    return cast<TypeAliasTemplateDecl>(
 
             RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
 
 
  /// Retrieve the previous declaration of this function template, or
 
  /// nullptr if no such declaration exists.
 
  TypeAliasTemplateDecl *getPreviousDecl() {
 
    return cast_or_null<TypeAliasTemplateDecl>(
 
             static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
 
  }
 
  const TypeAliasTemplateDecl *getPreviousDecl() const {
 
    return cast_or_null<TypeAliasTemplateDecl>(
 
             static_cast<const RedeclarableTemplateDecl *>(
 
               this)->getPreviousDecl());
 
  }
 
 
 
  TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() const {
 
    return cast_or_null<TypeAliasTemplateDecl>(
 
             RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
 
  }
 
 
 
  /// Create a function template node.
 
  static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC,
 
                                       SourceLocation L,
 
                                       DeclarationName Name,
 
                                       TemplateParameterList *Params,
 
                                       NamedDecl *Decl);
 
 
 
  /// Create an empty alias template node.
 
  static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  // Implement isa/cast/dyncast support
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
 
};
 
 
 
/// Declaration of a function specialization at template class scope.
 
///
 
/// For example:
 
/// \code
 
/// template <class T>
 
/// class A {
 
///    template <class U> void foo(U a) { }
 
///    template<> void foo(int a) { }
 
/// }
 
/// \endcode
 
///
 
/// "template<> foo(int a)" will be saved in Specialization as a normal
 
/// CXXMethodDecl. Then during an instantiation of class A, it will be
 
/// transformed into an actual function specialization.
 
///
 
/// FIXME: This is redundant; we could store the same information directly on
 
/// the CXXMethodDecl as a DependentFunctionTemplateSpecializationInfo.
 
class ClassScopeFunctionSpecializationDecl : public Decl {
 
  CXXMethodDecl *Specialization;
 
  const ASTTemplateArgumentListInfo *TemplateArgs;
 
 
 
  ClassScopeFunctionSpecializationDecl(
 
      DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD,
 
      const ASTTemplateArgumentListInfo *TemplArgs)
 
      : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
 
        Specialization(FD), TemplateArgs(TemplArgs) {}
 
 
 
  ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
 
      : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
 
 
 
  virtual void anchor();
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  CXXMethodDecl *getSpecialization() const { return Specialization; }
 
  bool hasExplicitTemplateArgs() const { return TemplateArgs; }
 
  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
 
    return TemplateArgs;
 
  }
 
 
 
  static ClassScopeFunctionSpecializationDecl *
 
  Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD,
 
         bool HasExplicitTemplateArgs,
 
         const TemplateArgumentListInfo &TemplateArgs) {
 
    return new (C, DC) ClassScopeFunctionSpecializationDecl(
 
        DC, Loc, FD,
 
        HasExplicitTemplateArgs
 
            ? ASTTemplateArgumentListInfo::Create(C, TemplateArgs)
 
            : nullptr);
 
  }
 
 
 
  static ClassScopeFunctionSpecializationDecl *
 
  CreateDeserialized(ASTContext &Context, unsigned ID);
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K == Decl::ClassScopeFunctionSpecialization;
 
  }
 
};
 
 
 
/// Represents a variable template specialization, which refers to
 
/// a variable template with a given set of template arguments.
 
///
 
/// Variable template specializations represent both explicit
 
/// specializations of variable templates, as in the example below, and
 
/// implicit instantiations of variable templates.
 
///
 
/// \code
 
/// template<typename T> constexpr T pi = T(3.1415926535897932385);
 
///
 
/// template<>
 
/// constexpr float pi<float>; // variable template specialization pi<float>
 
/// \endcode
 
class VarTemplateSpecializationDecl : public VarDecl,
 
                                      public llvm::FoldingSetNode {
 
 
 
  /// Structure that stores information about a variable template
 
  /// specialization that was instantiated from a variable template partial
 
  /// specialization.
 
  struct SpecializedPartialSpecialization {
 
    /// The variable template partial specialization from which this
 
    /// variable template specialization was instantiated.
 
    VarTemplatePartialSpecializationDecl *PartialSpecialization;
 
 
 
    /// The template argument list deduced for the variable template
 
    /// partial specialization itself.
 
    const TemplateArgumentList *TemplateArgs;
 
  };
 
 
 
  /// The template that this specialization specializes.
 
  llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *>
 
  SpecializedTemplate;
 
 
 
  /// Further info for explicit template specialization/instantiation.
 
  struct ExplicitSpecializationInfo {
 
    /// The type-as-written.
 
    TypeSourceInfo *TypeAsWritten = nullptr;
 
 
 
    /// The location of the extern keyword.
 
    SourceLocation ExternLoc;
 
 
 
    /// The location of the template keyword.
 
    SourceLocation TemplateKeywordLoc;
 
 
 
    ExplicitSpecializationInfo() = default;
 
  };
 
 
 
  /// Further info for explicit template specialization/instantiation.
 
  /// Does not apply to implicit specializations.
 
  ExplicitSpecializationInfo *ExplicitInfo = nullptr;
 
 
 
  /// The template arguments used to describe this specialization.
 
  const TemplateArgumentList *TemplateArgs;
 
  const ASTTemplateArgumentListInfo *TemplateArgsInfo = nullptr;
 
 
 
  /// The point where this template was instantiated (if any).
 
  SourceLocation PointOfInstantiation;
 
 
 
  /// The kind of specialization this declaration refers to.
 
  /// Really a value of type TemplateSpecializationKind.
 
  unsigned SpecializationKind : 3;
 
 
 
  /// Whether this declaration is a complete definition of the
 
  /// variable template specialization. We can't otherwise tell apart
 
  /// an instantiated declaration from an instantiated definition with
 
  /// no initializer.
 
  unsigned IsCompleteDefinition : 1;
 
 
 
protected:
 
  VarTemplateSpecializationDecl(Kind DK, ASTContext &Context, DeclContext *DC,
 
                                SourceLocation StartLoc, SourceLocation IdLoc,
 
                                VarTemplateDecl *SpecializedTemplate,
 
                                QualType T, TypeSourceInfo *TInfo,
 
                                StorageClass S,
 
                                ArrayRef<TemplateArgument> Args);
 
 
 
  explicit VarTemplateSpecializationDecl(Kind DK, ASTContext &Context);
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
  friend class VarDecl;
 
 
 
  static VarTemplateSpecializationDecl *
 
  Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
 
         SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
 
         TypeSourceInfo *TInfo, StorageClass S,
 
         ArrayRef<TemplateArgument> Args);
 
  static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
 
                                                           unsigned ID);
 
 
 
  void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
 
                            bool Qualified) const override;
 
 
 
  VarTemplateSpecializationDecl *getMostRecentDecl() {
 
    VarDecl *Recent = static_cast<VarDecl *>(this)->getMostRecentDecl();
 
    return cast<VarTemplateSpecializationDecl>(Recent);
 
  }
 
 
 
  /// Retrieve the template that this specialization specializes.
 
  VarTemplateDecl *getSpecializedTemplate() const;
 
 
 
  /// Retrieve the template arguments of the variable template
 
  /// specialization.
 
  const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }
 
 
 
  // TODO: Always set this when creating the new specialization?
 
  void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
 
  void setTemplateArgsInfo(const ASTTemplateArgumentListInfo *ArgsInfo);
 
 
 
  const ASTTemplateArgumentListInfo *getTemplateArgsInfo() const {
 
    return TemplateArgsInfo;
 
  }
 
 
 
  /// Determine the kind of specialization that this
 
  /// declaration represents.
 
  TemplateSpecializationKind getSpecializationKind() const {
 
    return static_cast<TemplateSpecializationKind>(SpecializationKind);
 
  }
 
 
 
  bool isExplicitSpecialization() const {
 
    return getSpecializationKind() == TSK_ExplicitSpecialization;
 
  }
 
 
 
  bool isClassScopeExplicitSpecialization() const {
 
    return isExplicitSpecialization() &&
 
           isa<CXXRecordDecl>(getLexicalDeclContext());
 
  }
 
 
 
  /// True if this declaration is an explicit specialization,
 
  /// explicit instantiation declaration, or explicit instantiation
 
  /// definition.
 
  bool isExplicitInstantiationOrSpecialization() const {
 
    return isTemplateExplicitInstantiationOrSpecialization(
 
        getTemplateSpecializationKind());
 
  }
 
 
 
  void setSpecializationKind(TemplateSpecializationKind TSK) {
 
    SpecializationKind = TSK;
 
  }
 
 
 
  /// Get the point of instantiation (if any), or null if none.
 
  SourceLocation getPointOfInstantiation() const {
 
    return PointOfInstantiation;
 
  }
 
 
 
  void setPointOfInstantiation(SourceLocation Loc) {
 
    assert(Loc.isValid() && "point of instantiation must be valid!");
 
    PointOfInstantiation = Loc;
 
  }
 
 
 
  void setCompleteDefinition() { IsCompleteDefinition = true; }
 
 
 
  /// If this variable template specialization is an instantiation of
 
  /// a template (rather than an explicit specialization), return the
 
  /// variable template or variable template partial specialization from which
 
  /// it was instantiated.
 
  llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
 
  getInstantiatedFrom() const {
 
    if (!isTemplateInstantiation(getSpecializationKind()))
 
      return llvm::PointerUnion<VarTemplateDecl *,
 
                                VarTemplatePartialSpecializationDecl *>();
 
 
 
    return getSpecializedTemplateOrPartial();
 
  }
 
 
 
  /// Retrieve the variable template or variable template partial
 
  /// specialization which was specialized by this.
 
  llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
 
  getSpecializedTemplateOrPartial() const {
 
    if (const auto *PartialSpec =
 
            SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
 
      return PartialSpec->PartialSpecialization;
 
 
 
    return SpecializedTemplate.get<VarTemplateDecl *>();
 
  }
 
 
 
  /// Retrieve the set of template arguments that should be used
 
  /// to instantiate the initializer of the variable template or variable
 
  /// template partial specialization from which this variable template
 
  /// specialization was instantiated.
 
  ///
 
  /// \returns For a variable template specialization instantiated from the
 
  /// primary template, this function will return the same template arguments
 
  /// as getTemplateArgs(). For a variable template specialization instantiated
 
  /// from a variable template partial specialization, this function will the
 
  /// return deduced template arguments for the variable template partial
 
  /// specialization itself.
 
  const TemplateArgumentList &getTemplateInstantiationArgs() const {
 
    if (const auto *PartialSpec =
 
            SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
 
      return *PartialSpec->TemplateArgs;
 
 
 
    return getTemplateArgs();
 
  }
 
 
 
  /// Note that this variable template specialization is actually an
 
  /// instantiation of the given variable template partial specialization whose
 
  /// template arguments have been deduced.
 
  void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
 
                          const TemplateArgumentList *TemplateArgs) {
 
    assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
 
           "Already set to a variable template partial specialization!");
 
    auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
 
    PS->PartialSpecialization = PartialSpec;
 
    PS->TemplateArgs = TemplateArgs;
 
    SpecializedTemplate = PS;
 
  }
 
 
 
  /// Note that this variable template specialization is an instantiation
 
  /// of the given variable template.
 
  void setInstantiationOf(VarTemplateDecl *TemplDecl) {
 
    assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
 
           "Previously set to a variable template partial specialization!");
 
    SpecializedTemplate = TemplDecl;
 
  }
 
 
 
  /// Sets the type of this specialization as it was written by
 
  /// the user.
 
  void setTypeAsWritten(TypeSourceInfo *T) {
 
    if (!ExplicitInfo)
 
      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
 
    ExplicitInfo->TypeAsWritten = T;
 
  }
 
 
 
  /// Gets the type of this specialization as it was written by
 
  /// the user, if it was so written.
 
  TypeSourceInfo *getTypeAsWritten() const {
 
    return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
 
  }
 
 
 
  /// Gets the location of the extern keyword, if present.
 
  SourceLocation getExternLoc() const {
 
    return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
 
  }
 
 
 
  /// Sets the location of the extern keyword.
 
  void setExternLoc(SourceLocation Loc) {
 
    if (!ExplicitInfo)
 
      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
 
    ExplicitInfo->ExternLoc = Loc;
 
  }
 
 
 
  /// Sets the location of the template keyword.
 
  void setTemplateKeywordLoc(SourceLocation Loc) {
 
    if (!ExplicitInfo)
 
      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
 
    ExplicitInfo->TemplateKeywordLoc = Loc;
 
  }
 
 
 
  /// Gets the location of the template keyword, if present.
 
  SourceLocation getTemplateKeywordLoc() const {
 
    return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY {
 
    if (isExplicitSpecialization()) {
 
      if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsInfo())
 
        return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
 
    }
 
    return VarDecl::getSourceRange();
 
  }
 
 
 
  void Profile(llvm::FoldingSetNodeID &ID) const {
 
    Profile(ID, TemplateArgs->asArray(), getASTContext());
 
  }
 
 
 
  static void Profile(llvm::FoldingSetNodeID &ID,
 
                      ArrayRef<TemplateArgument> TemplateArgs,
 
                      ASTContext &Context) {
 
    ID.AddInteger(TemplateArgs.size());
 
    for (const TemplateArgument &TemplateArg : TemplateArgs)
 
      TemplateArg.Profile(ID, Context);
 
  }
 
 
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K >= firstVarTemplateSpecialization &&
 
           K <= lastVarTemplateSpecialization;
 
  }
 
};
 
 
 
class VarTemplatePartialSpecializationDecl
 
    : public VarTemplateSpecializationDecl {
 
  /// The list of template parameters
 
  TemplateParameterList *TemplateParams = nullptr;
 
 
 
  /// The source info for the template arguments as written.
 
  /// FIXME: redundant with TypeAsWritten?
 
  const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
 
 
 
  /// The variable template partial specialization from which this
 
  /// variable template partial specialization was instantiated.
 
  ///
 
  /// The boolean value will be true to indicate that this variable template
 
  /// partial specialization was specialized at this level.
 
  llvm::PointerIntPair<VarTemplatePartialSpecializationDecl *, 1, bool>
 
  InstantiatedFromMember;
 
 
 
  VarTemplatePartialSpecializationDecl(
 
      ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
 
      SourceLocation IdLoc, TemplateParameterList *Params,
 
      VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
 
      StorageClass S, ArrayRef<TemplateArgument> Args,
 
      const ASTTemplateArgumentListInfo *ArgInfos);
 
 
 
  VarTemplatePartialSpecializationDecl(ASTContext &Context)
 
      : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization,
 
                                      Context),
 
        InstantiatedFromMember(nullptr, false) {}
 
 
 
  void anchor() override;
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  static VarTemplatePartialSpecializationDecl *
 
  Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
 
         SourceLocation IdLoc, TemplateParameterList *Params,
 
         VarTemplateDecl *SpecializedTemplate, QualType T,
 
         TypeSourceInfo *TInfo, StorageClass S, ArrayRef<TemplateArgument> Args,
 
         const TemplateArgumentListInfo &ArgInfos);
 
 
 
  static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C,
 
                                                                  unsigned ID);
 
 
 
  VarTemplatePartialSpecializationDecl *getMostRecentDecl() {
 
    return cast<VarTemplatePartialSpecializationDecl>(
 
             static_cast<VarTemplateSpecializationDecl *>(
 
               this)->getMostRecentDecl());
 
  }
 
 
 
  /// Get the list of template parameters
 
  TemplateParameterList *getTemplateParameters() const {
 
    return TemplateParams;
 
  }
 
 
 
  /// Get the template arguments as written.
 
  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
 
    return ArgsAsWritten;
 
  }
 
 
 
  /// \brief All associated constraints of this partial specialization,
 
  /// including the requires clause and any constraints derived from
 
  /// constrained-parameters.
 
  ///
 
  /// The constraints in the resulting list are to be treated as if in a
 
  /// conjunction ("and").
 
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
 
    TemplateParams->getAssociatedConstraints(AC);
 
  }
 
 
 
  bool hasAssociatedConstraints() const {
 
    return TemplateParams->hasAssociatedConstraints();
 
  }
 
 
 
  /// \brief Retrieve the member variable template partial specialization from
 
  /// which this particular variable template partial specialization was
 
  /// instantiated.
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// struct Outer {
 
  ///   template<typename U> U Inner;
 
  ///   template<typename U> U* Inner<U*> = (U*)(0); // #1
 
  /// };
 
  ///
 
  /// template int* Outer<float>::Inner<int*>;
 
  /// \endcode
 
  ///
 
  /// In this example, the instantiation of \c Outer<float>::Inner<int*> will
 
  /// end up instantiating the partial specialization
 
  /// \c Outer<float>::Inner<U*>, which itself was instantiated from the
 
  /// variable template partial specialization \c Outer<T>::Inner<U*>. Given
 
  /// \c Outer<float>::Inner<U*>, this function would return
 
  /// \c Outer<T>::Inner<U*>.
 
  VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() const {
 
    const auto *First =
 
        cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
 
    return First->InstantiatedFromMember.getPointer();
 
  }
 
 
 
  void
 
  setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) {
 
    auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
 
    First->InstantiatedFromMember.setPointer(PartialSpec);
 
  }
 
 
 
  /// Determines whether this variable template partial specialization
 
  /// was a specialization of a member partial specialization.
 
  ///
 
  /// In the following example, the member template partial specialization
 
  /// \c X<int>::Inner<T*> is a member specialization.
 
  ///
 
  /// \code
 
  /// template<typename T>
 
  /// struct X {
 
  ///   template<typename U> U Inner;
 
  ///   template<typename U> U* Inner<U*> = (U*)(0);
 
  /// };
 
  ///
 
  /// template<> template<typename T>
 
  /// U* X<int>::Inner<T*> = (T*)(0) + 1;
 
  /// \endcode
 
  bool isMemberSpecialization() {
 
    const auto *First =
 
        cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
 
    return First->InstantiatedFromMember.getInt();
 
  }
 
 
 
  /// Note that this member template is a specialization.
 
  void setMemberSpecialization() {
 
    auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
 
    assert(First->InstantiatedFromMember.getPointer() &&
 
           "Only member templates can be member template specializations");
 
    return First->InstantiatedFromMember.setInt(true);
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY {
 
    if (isExplicitSpecialization()) {
 
      if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsAsWritten())
 
        return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
 
    }
 
    return VarDecl::getSourceRange();
 
  }
 
 
 
  void Profile(llvm::FoldingSetNodeID &ID) const {
 
    Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
 
            getASTContext());
 
  }
 
 
 
  static void
 
  Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
 
          TemplateParameterList *TPL, ASTContext &Context);
 
 
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  static bool classofKind(Kind K) {
 
    return K == VarTemplatePartialSpecialization;
 
  }
 
};
 
 
 
/// Declaration of a variable template.
 
class VarTemplateDecl : public RedeclarableTemplateDecl {
 
protected:
 
  /// Data that is common to all of the declarations of a given
 
  /// variable template.
 
  struct Common : CommonBase {
 
    /// The variable template specializations for this variable
 
    /// template, including explicit specializations and instantiations.
 
    llvm::FoldingSetVector<VarTemplateSpecializationDecl> Specializations;
 
 
 
    /// The variable template partial specializations for this variable
 
    /// template.
 
    llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>
 
    PartialSpecializations;
 
 
 
    Common() = default;
 
  };
 
 
 
  /// Retrieve the set of specializations of this variable template.
 
  llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
 
  getSpecializations() const;
 
 
 
  /// Retrieve the set of partial specializations of this class
 
  /// template.
 
  llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
 
  getPartialSpecializations() const;
 
 
 
  VarTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
 
                  DeclarationName Name, TemplateParameterList *Params,
 
                  NamedDecl *Decl)
 
      : RedeclarableTemplateDecl(VarTemplate, C, DC, L, Name, Params, Decl) {}
 
 
 
  CommonBase *newCommon(ASTContext &C) const override;
 
 
 
  Common *getCommonPtr() const {
 
    return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
 
  }
 
 
 
public:
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
 
 
  /// Load any lazily-loaded specializations from the external source.
 
  void LoadLazySpecializations() const;
 
 
 
  /// Get the underlying variable declarations of the template.
 
  VarDecl *getTemplatedDecl() const {
 
    return static_cast<VarDecl *>(TemplatedDecl);
 
  }
 
 
 
  /// Returns whether this template declaration defines the primary
 
  /// variable pattern.
 
  bool isThisDeclarationADefinition() const {
 
    return getTemplatedDecl()->isThisDeclarationADefinition();
 
  }
 
 
 
  VarTemplateDecl *getDefinition();
 
 
 
  /// Create a variable template node.
 
  static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC,
 
                                 SourceLocation L, DeclarationName Name,
 
                                 TemplateParameterList *Params,
 
                                 VarDecl *Decl);
 
 
 
  /// Create an empty variable template node.
 
  static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  /// Return the specialization with the provided arguments if it exists,
 
  /// otherwise return the insertion point.
 
  VarTemplateSpecializationDecl *
 
  findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos);
 
 
 
  /// Insert the specified specialization knowing that it is not already
 
  /// in. InsertPos must be obtained from findSpecialization.
 
  void AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos);
 
 
 
  VarTemplateDecl *getCanonicalDecl() override {
 
    return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
  const VarTemplateDecl *getCanonicalDecl() const {
 
    return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl());
 
  }
 
 
 
  /// Retrieve the previous declaration of this variable template, or
 
  /// nullptr if no such declaration exists.
 
  VarTemplateDecl *getPreviousDecl() {
 
    return cast_or_null<VarTemplateDecl>(
 
        static_cast<RedeclarableTemplateDecl *>(this)->getPreviousDecl());
 
  }
 
  const VarTemplateDecl *getPreviousDecl() const {
 
    return cast_or_null<VarTemplateDecl>(
 
            static_cast<const RedeclarableTemplateDecl *>(
 
              this)->getPreviousDecl());
 
  }
 
 
 
  VarTemplateDecl *getMostRecentDecl() {
 
    return cast<VarTemplateDecl>(
 
        static_cast<RedeclarableTemplateDecl *>(this)->getMostRecentDecl());
 
  }
 
  const VarTemplateDecl *getMostRecentDecl() const {
 
    return const_cast<VarTemplateDecl *>(this)->getMostRecentDecl();
 
  }
 
 
 
  VarTemplateDecl *getInstantiatedFromMemberTemplate() const {
 
    return cast_or_null<VarTemplateDecl>(
 
        RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate());
 
  }
 
 
 
  /// Return the partial specialization with the provided arguments if it
 
  /// exists, otherwise return the insertion point.
 
  VarTemplatePartialSpecializationDecl *
 
  findPartialSpecialization(ArrayRef<TemplateArgument> Args,
 
                            TemplateParameterList *TPL, void *&InsertPos);
 
 
 
  /// Insert the specified partial specialization knowing that it is not
 
  /// already in. InsertPos must be obtained from findPartialSpecialization.
 
  void AddPartialSpecialization(VarTemplatePartialSpecializationDecl *D,
 
                                void *InsertPos);
 
 
 
  /// Retrieve the partial specializations as an ordered list.
 
  void getPartialSpecializations(
 
      SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) const;
 
 
 
  /// Find a variable template partial specialization which was
 
  /// instantiated
 
  /// from the given member partial specialization.
 
  ///
 
  /// \param D a member variable template partial specialization.
 
  ///
 
  /// \returns the variable template partial specialization which was
 
  /// instantiated
 
  /// from the given member partial specialization, or nullptr if no such
 
  /// partial specialization exists.
 
  VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember(
 
      VarTemplatePartialSpecializationDecl *D);
 
 
 
  using spec_iterator = SpecIterator<VarTemplateSpecializationDecl>;
 
  using spec_range = llvm::iterator_range<spec_iterator>;
 
 
 
  spec_range specializations() const {
 
    return spec_range(spec_begin(), spec_end());
 
  }
 
 
 
  spec_iterator spec_begin() const {
 
    return makeSpecIterator(getSpecializations(), false);
 
  }
 
 
 
  spec_iterator spec_end() const {
 
    return makeSpecIterator(getSpecializations(), true);
 
  }
 
 
 
  // Implement isa/cast/dyncast support
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == VarTemplate; }
 
};
 
 
 
/// Declaration of a C++20 concept.
 
class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
 
protected:
 
  Expr *ConstraintExpr;
 
 
 
  ConceptDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
 
              TemplateParameterList *Params, Expr *ConstraintExpr)
 
      : TemplateDecl(Concept, DC, L, Name, Params),
 
        ConstraintExpr(ConstraintExpr) {};
 
public:
 
  static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
 
                             SourceLocation L, DeclarationName Name,
 
                             TemplateParameterList *Params,
 
                             Expr *ConstraintExpr);
 
  static ConceptDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
 
 
  Expr *getConstraintExpr() const {
 
    return ConstraintExpr;
 
  }
 
 
 
  SourceRange getSourceRange() const override LLVM_READONLY {
 
    return SourceRange(getTemplateParameters()->getTemplateLoc(),
 
                       ConstraintExpr->getEndLoc());
 
  }
 
 
 
  bool isTypeConcept() const {
 
    return isa<TemplateTypeParmDecl>(getTemplateParameters()->getParam(0));
 
  }
 
 
 
  ConceptDecl *getCanonicalDecl() override {
 
    return cast<ConceptDecl>(getPrimaryMergedDecl(this));
 
  }
 
  const ConceptDecl *getCanonicalDecl() const {
 
    return const_cast<ConceptDecl *>(this)->getCanonicalDecl();
 
  }
 
 
 
  // Implement isa/cast/dyncast/etc.
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == Concept; }
 
 
 
  friend class ASTReader;
 
  friend class ASTDeclReader;
 
  friend class ASTDeclWriter;
 
};
 
 
 
// An implementation detail of ConceptSpecialicationExpr that holds the template
 
// arguments, so we can later use this to reconstitute the template arguments
 
// during constraint checking.
 
class ImplicitConceptSpecializationDecl final
 
    : public Decl,
 
      private llvm::TrailingObjects<ImplicitConceptSpecializationDecl,
 
                                    TemplateArgument> {
 
  unsigned NumTemplateArgs;
 
 
 
  ImplicitConceptSpecializationDecl(DeclContext *DC, SourceLocation SL,
 
                                    ArrayRef<TemplateArgument> ConvertedArgs);
 
  ImplicitConceptSpecializationDecl(EmptyShell Empty, unsigned NumTemplateArgs);
 
 
 
public:
 
  static ImplicitConceptSpecializationDecl *
 
  Create(const ASTContext &C, DeclContext *DC, SourceLocation SL,
 
         ArrayRef<TemplateArgument> ConvertedArgs);
 
  static ImplicitConceptSpecializationDecl *
 
  CreateDeserialized(const ASTContext &C, unsigned ID,
 
                     unsigned NumTemplateArgs);
 
 
 
  ArrayRef<TemplateArgument> getTemplateArguments() const {
 
    return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
 
                                      NumTemplateArgs);
 
  }
 
  void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
 
 
 
  static bool classofKind(Kind K) { return K == ImplicitConceptSpecialization; }
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
 
 
  friend TrailingObjects;
 
  friend class ASTDeclReader;
 
};
 
 
 
/// A template parameter object.
 
///
 
/// Template parameter objects represent values of class type used as template
 
/// arguments. There is one template parameter object for each such distinct
 
/// value used as a template argument across the program.
 
///
 
/// \code
 
/// struct A { int x, y; };
 
/// template<A> struct S;
 
/// S<A{1, 2}> s1;
 
/// S<A{1, 2}> s2; // same type, argument is same TemplateParamObjectDecl.
 
/// \endcode
 
class TemplateParamObjectDecl : public ValueDecl,
 
                                public Mergeable<TemplateParamObjectDecl>,
 
                                public llvm::FoldingSetNode {
 
private:
 
  /// The value of this template parameter object.
 
  APValue Value;
 
 
 
  TemplateParamObjectDecl(DeclContext *DC, QualType T, const APValue &V)
 
      : ValueDecl(TemplateParamObject, DC, SourceLocation(), DeclarationName(),
 
                  T),
 
        Value(V) {}
 
 
 
  static TemplateParamObjectDecl *Create(const ASTContext &C, QualType T,
 
                                         const APValue &V);
 
  static TemplateParamObjectDecl *CreateDeserialized(ASTContext &C,
 
                                                     unsigned ID);
 
 
 
  /// Only ASTContext::getTemplateParamObjectDecl and deserialization
 
  /// create these.
 
  friend class ASTContext;
 
  friend class ASTReader;
 
  friend class ASTDeclReader;
 
 
 
public:
 
  /// Print this template parameter object in a human-readable format.
 
  void printName(llvm::raw_ostream &OS,
 
                 const PrintingPolicy &Policy) const override;
 
 
 
  /// Print this object as an equivalent expression.
 
  void printAsExpr(llvm::raw_ostream &OS) const;
 
  void printAsExpr(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
 
 
 
  /// Print this object as an initializer suitable for a variable of the
 
  /// object's type.
 
  void printAsInit(llvm::raw_ostream &OS) const;
 
  void printAsInit(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
 
 
 
  const APValue &getValue() const { return Value; }
 
 
 
  static void Profile(llvm::FoldingSetNodeID &ID, QualType T,
 
                      const APValue &V) {
 
    ID.AddPointer(T.getCanonicalType().getAsOpaquePtr());
 
    V.Profile(ID);
 
  }
 
  void Profile(llvm::FoldingSetNodeID &ID) {
 
    Profile(ID, getType(), getValue());
 
  }
 
 
 
  TemplateParamObjectDecl *getCanonicalDecl() override {
 
    return getFirstDecl();
 
  }
 
  const TemplateParamObjectDecl *getCanonicalDecl() const {
 
    return getFirstDecl();
 
  }
 
 
 
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
 
  static bool classofKind(Kind K) { return K == TemplateParamObject; }
 
};
 
 
 
inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
 
  if (auto *PD = P.dyn_cast<TemplateTypeParmDecl *>())
 
    return PD;
 
  if (auto *PD = P.dyn_cast<NonTypeTemplateParmDecl *>())
 
    return PD;
 
  return P.get<TemplateTemplateParmDecl *>();
 
}
 
 
 
inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
 
  auto *TD = dyn_cast<TemplateDecl>(D);
 
  return TD && (isa<ClassTemplateDecl>(TD) ||
 
                isa<ClassTemplatePartialSpecializationDecl>(TD) ||
 
                isa<TypeAliasTemplateDecl>(TD) ||
 
                isa<TemplateTemplateParmDecl>(TD))
 
             ? TD
 
             : nullptr;
 
}
 
 
 
/// Check whether the template parameter is a pack expansion, and if so,
 
/// determine the number of parameters produced by that expansion. For instance:
 
///
 
/// \code
 
/// template<typename ...Ts> struct A {
 
///   template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B;
 
/// };
 
/// \endcode
 
///
 
/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
 
/// is not a pack expansion, so returns an empty Optional.
 
inline std::optional<unsigned> getExpandedPackSize(const NamedDecl *Param) {
 
  if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
 
    if (TTP->isExpandedParameterPack())
 
      return TTP->getNumExpansionParameters();
 
  }
 
 
 
  if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
 
    if (NTTP->isExpandedParameterPack())
 
      return NTTP->getNumExpansionTypes();
 
  }
 
 
 
  if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) {
 
    if (TTP->isExpandedParameterPack())
 
      return TTP->getNumExpansionTemplateParameters();
 
  }
 
 
 
  return std::nullopt;
 
}
 
 
 
/// Internal helper used by Subst* nodes to retrieve the parameter list
 
/// for their AssociatedDecl.
 
TemplateParameterList *getReplacedTemplateParameterList(Decl *D);
 
 
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_AST_DECLTEMPLATE_H