| //===- SemaTemplate.h - 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 |
| //===----------------------------------------------------------------------===// |
| // |
| // This file provides types used in the semantic analysis of C++ templates. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_SEMA_TEMPLATE_H |
| #define LLVM_CLANG_SEMA_TEMPLATE_H |
| |
| #include "clang/AST/DeclTemplate.h" |
| #include "clang/AST/DeclVisitor.h" |
| #include "clang/AST/TemplateBase.h" |
| #include "clang/AST/Type.h" |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Sema/Sema.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/PointerUnion.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include <cassert> |
| #include <utility> |
| |
| namespace clang { |
| |
| class ASTContext; |
| class BindingDecl; |
| class CXXMethodDecl; |
| class Decl; |
| class DeclaratorDecl; |
| class DeclContext; |
| class EnumDecl; |
| class FunctionDecl; |
| class NamedDecl; |
| class ParmVarDecl; |
| class TagDecl; |
| class TypedefNameDecl; |
| class TypeSourceInfo; |
| class VarDecl; |
| |
| /// Data structure that captures multiple levels of template argument |
| /// lists for use in template instantiation. |
| /// |
| /// Multiple levels of template arguments occur when instantiating the |
| /// definitions of member templates. For example: |
| /// |
| /// \code |
| /// template<typename T> |
| /// struct X { |
| /// template<T Value> |
| /// struct Y { |
| /// void f(); |
| /// }; |
| /// }; |
| /// \endcode |
| /// |
| /// When instantiating X<int>::Y<17>::f, the multi-level template argument |
| /// list will contain a template argument list (int) at depth 0 and a |
| /// template argument list (17) at depth 1. |
| class MultiLevelTemplateArgumentList { |
| /// The template argument list at a certain template depth |
| using ArgList = ArrayRef<TemplateArgument>; |
| |
| /// The template argument lists, stored from the innermost template |
| /// argument list (first) to the outermost template argument list (last). |
| SmallVector<ArgList, 4> TemplateArgumentLists; |
| |
| /// The number of outer levels of template arguments that are not |
| /// being substituted. |
| unsigned NumRetainedOuterLevels = 0; |
| |
| public: |
| /// Construct an empty set of template argument lists. |
| MultiLevelTemplateArgumentList() = default; |
| |
| /// Construct a single-level template argument list. |
| explicit |
| MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { |
| addOuterTemplateArguments(&TemplateArgs); |
| } |
| |
| /// Determine the number of levels in this template argument |
| /// list. |
| unsigned getNumLevels() const { |
| return TemplateArgumentLists.size() + NumRetainedOuterLevels; |
| } |
| |
| /// Determine the number of substituted levels in this template |
| /// argument list. |
| unsigned getNumSubstitutedLevels() const { |
| return TemplateArgumentLists.size(); |
| } |
| |
| /// Retrieve the template argument at a given depth and index. |
| const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { |
| assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); |
| assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); |
| return TemplateArgumentLists[getNumLevels() - Depth - 1][Index]; |
| } |
| |
| /// Determine whether there is a non-NULL template argument at the |
| /// given depth and index. |
| /// |
| /// There must exist a template argument list at the given depth. |
| bool hasTemplateArgument(unsigned Depth, unsigned Index) const { |
| assert(Depth < getNumLevels()); |
| |
| if (Depth < NumRetainedOuterLevels) |
| return false; |
| |
| if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size()) |
| return false; |
| |
| return !(*this)(Depth, Index).isNull(); |
| } |
| |
| /// Clear out a specific template argument. |
| void setArgument(unsigned Depth, unsigned Index, |
| TemplateArgument Arg) { |
| assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels()); |
| assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size()); |
| const_cast<TemplateArgument&>( |
| TemplateArgumentLists[getNumLevels() - Depth - 1][Index]) |
| = Arg; |
| } |
| |
| /// Add a new outermost level to the multi-level template argument |
| /// list. |
| void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { |
| addOuterTemplateArguments(ArgList(TemplateArgs->data(), |
| TemplateArgs->size())); |
| } |
| |
| /// Add a new outmost level to the multi-level template argument |
| /// list. |
| void addOuterTemplateArguments(ArgList Args) { |
| assert(!NumRetainedOuterLevels && |
| "substituted args outside retained args?"); |
| TemplateArgumentLists.push_back(Args); |
| } |
| |
| /// Add an outermost level that we are not substituting. We have no |
| /// arguments at this level, and do not remove it from the depth of inner |
| /// template parameters that we instantiate. |
| void addOuterRetainedLevel() { |
| ++NumRetainedOuterLevels; |
| } |
| |
| /// Retrieve the innermost template argument list. |
| const ArgList &getInnermost() const { |
| return TemplateArgumentLists.front(); |
| } |
| }; |
| |
| /// The context in which partial ordering of function templates occurs. |
| enum TPOC { |
| /// Partial ordering of function templates for a function call. |
| TPOC_Call, |
| |
| /// Partial ordering of function templates for a call to a |
| /// conversion function. |
| TPOC_Conversion, |
| |
| /// Partial ordering of function templates in other contexts, e.g., |
| /// taking the address of a function template or matching a function |
| /// template specialization to a function template. |
| TPOC_Other |
| }; |
| |
| // This is lame but unavoidable in a world without forward |
| // declarations of enums. The alternatives are to either pollute |
| // Sema.h (by including this file) or sacrifice type safety (by |
| // making Sema.h declare things as enums). |
| class TemplatePartialOrderingContext { |
| TPOC Value; |
| |
| public: |
| TemplatePartialOrderingContext(TPOC Value) : Value(Value) {} |
| |
| operator TPOC() const { return Value; } |
| }; |
| |
| /// Captures a template argument whose value has been deduced |
| /// via c++ template argument deduction. |
| class DeducedTemplateArgument : public TemplateArgument { |
| /// For a non-type template argument, whether the value was |
| /// deduced from an array bound. |
| bool DeducedFromArrayBound = false; |
| |
| public: |
| DeducedTemplateArgument() = default; |
| |
| DeducedTemplateArgument(const TemplateArgument &Arg, |
| bool DeducedFromArrayBound = false) |
| : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) {} |
| |
| /// Construct an integral non-type template argument that |
| /// has been deduced, possibly from an array bound. |
| DeducedTemplateArgument(ASTContext &Ctx, |
| const llvm::APSInt &Value, |
| QualType ValueType, |
| bool DeducedFromArrayBound) |
| : TemplateArgument(Ctx, Value, ValueType), |
| DeducedFromArrayBound(DeducedFromArrayBound) {} |
| |
| /// For a non-type template argument, determine whether the |
| /// template argument was deduced from an array bound. |
| bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } |
| |
| /// Specify whether the given non-type template argument |
| /// was deduced from an array bound. |
| void setDeducedFromArrayBound(bool Deduced) { |
| DeducedFromArrayBound = Deduced; |
| } |
| }; |
| |
| /// A stack-allocated class that identifies which local |
| /// variable declaration instantiations are present in this scope. |
| /// |
| /// A new instance of this class type will be created whenever we |
| /// instantiate a new function declaration, which will have its own |
| /// set of parameter declarations. |
| class LocalInstantiationScope { |
| public: |
| /// A set of declarations. |
| using DeclArgumentPack = SmallVector<VarDecl *, 4>; |
| |
| private: |
| /// Reference to the semantic analysis that is performing |
| /// this template instantiation. |
| Sema &SemaRef; |
| |
| using LocalDeclsMap = |
| llvm::SmallDenseMap<const Decl *, |
| llvm::PointerUnion<Decl *, DeclArgumentPack *>, 4>; |
| |
| /// A mapping from local declarations that occur |
| /// within a template to their instantiations. |
| /// |
| /// This mapping is used during instantiation to keep track of, |
| /// e.g., function parameter and variable declarations. For example, |
| /// given: |
| /// |
| /// \code |
| /// template<typename T> T add(T x, T y) { return x + y; } |
| /// \endcode |
| /// |
| /// when we instantiate add<int>, we will introduce a mapping from |
| /// the ParmVarDecl for 'x' that occurs in the template to the |
| /// instantiated ParmVarDecl for 'x'. |
| /// |
| /// For a parameter pack, the local instantiation scope may contain a |
| /// set of instantiated parameters. This is stored as a DeclArgumentPack |
| /// pointer. |
| LocalDeclsMap LocalDecls; |
| |
| /// The set of argument packs we've allocated. |
| SmallVector<DeclArgumentPack *, 1> ArgumentPacks; |
| |
| /// The outer scope, which contains local variable |
| /// definitions from some other instantiation (that may not be |
| /// relevant to this particular scope). |
| LocalInstantiationScope *Outer; |
| |
| /// Whether we have already exited this scope. |
| bool Exited = false; |
| |
| /// Whether to combine this scope with the outer scope, such that |
| /// lookup will search our outer scope. |
| bool CombineWithOuterScope; |
| |
| /// If non-NULL, the template parameter pack that has been |
| /// partially substituted per C++0x [temp.arg.explicit]p9. |
| NamedDecl *PartiallySubstitutedPack = nullptr; |
| |
| /// If \c PartiallySubstitutedPack is non-null, the set of |
| /// explicitly-specified template arguments in that pack. |
| const TemplateArgument *ArgsInPartiallySubstitutedPack; |
| |
| /// If \c PartiallySubstitutedPack, the number of |
| /// explicitly-specified template arguments in |
| /// ArgsInPartiallySubstitutedPack. |
| unsigned NumArgsInPartiallySubstitutedPack; |
| |
| public: |
| LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) |
| : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), |
| CombineWithOuterScope(CombineWithOuterScope) { |
| SemaRef.CurrentInstantiationScope = this; |
| } |
| |
| LocalInstantiationScope(const LocalInstantiationScope &) = delete; |
| LocalInstantiationScope & |
| operator=(const LocalInstantiationScope &) = delete; |
| |
| ~LocalInstantiationScope() { |
| Exit(); |
| } |
| |
| const Sema &getSema() const { return SemaRef; } |
| |
| /// Exit this local instantiation scope early. |
| void Exit() { |
| if (Exited) |
| return; |
| |
| for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I) |
| delete ArgumentPacks[I]; |
| |
| SemaRef.CurrentInstantiationScope = Outer; |
| Exited = true; |
| } |
| |
| /// Clone this scope, and all outer scopes, down to the given |
| /// outermost scope. |
| LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) { |
| if (this == Outermost) return this; |
| |
| // Save the current scope from SemaRef since the LocalInstantiationScope |
| // will overwrite it on construction |
| LocalInstantiationScope *oldScope = SemaRef.CurrentInstantiationScope; |
| |
| LocalInstantiationScope *newScope = |
| new LocalInstantiationScope(SemaRef, CombineWithOuterScope); |
| |
| newScope->Outer = nullptr; |
| if (Outer) |
| newScope->Outer = Outer->cloneScopes(Outermost); |
| |
| newScope->PartiallySubstitutedPack = PartiallySubstitutedPack; |
| newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack; |
| newScope->NumArgsInPartiallySubstitutedPack = |
| NumArgsInPartiallySubstitutedPack; |
| |
| for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end(); |
| I != E; ++I) { |
| const Decl *D = I->first; |
| llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = |
| newScope->LocalDecls[D]; |
| if (I->second.is<Decl *>()) { |
| Stored = I->second.get<Decl *>(); |
| } else { |
| DeclArgumentPack *OldPack = I->second.get<DeclArgumentPack *>(); |
| DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack); |
| Stored = NewPack; |
| newScope->ArgumentPacks.push_back(NewPack); |
| } |
| } |
| // Restore the saved scope to SemaRef |
| SemaRef.CurrentInstantiationScope = oldScope; |
| return newScope; |
| } |
| |
| /// deletes the given scope, and all otuer scopes, down to the |
| /// given outermost scope. |
| static void deleteScopes(LocalInstantiationScope *Scope, |
| LocalInstantiationScope *Outermost) { |
| while (Scope && Scope != Outermost) { |
| LocalInstantiationScope *Out = Scope->Outer; |
| delete Scope; |
| Scope = Out; |
| } |
| } |
| |
| /// Find the instantiation of the declaration D within the current |
| /// instantiation scope. |
| /// |
| /// \param D The declaration whose instantiation we are searching for. |
| /// |
| /// \returns A pointer to the declaration or argument pack of declarations |
| /// to which the declaration \c D is instantiated, if found. Otherwise, |
| /// returns NULL. |
| llvm::PointerUnion<Decl *, DeclArgumentPack *> * |
| findInstantiationOf(const Decl *D); |
| |
| void InstantiatedLocal(const Decl *D, Decl *Inst); |
| void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst); |
| void MakeInstantiatedLocalArgPack(const Decl *D); |
| |
| /// Note that the given parameter pack has been partially substituted |
| /// via explicit specification of template arguments |
| /// (C++0x [temp.arg.explicit]p9). |
| /// |
| /// \param Pack The parameter pack, which will always be a template |
| /// parameter pack. |
| /// |
| /// \param ExplicitArgs The explicitly-specified template arguments provided |
| /// for this parameter pack. |
| /// |
| /// \param NumExplicitArgs The number of explicitly-specified template |
| /// arguments provided for this parameter pack. |
| void SetPartiallySubstitutedPack(NamedDecl *Pack, |
| const TemplateArgument *ExplicitArgs, |
| unsigned NumExplicitArgs); |
| |
| /// Reset the partially-substituted pack when it is no longer of |
| /// interest. |
| void ResetPartiallySubstitutedPack() { |
| assert(PartiallySubstitutedPack && "No partially-substituted pack"); |
| PartiallySubstitutedPack = nullptr; |
| ArgsInPartiallySubstitutedPack = nullptr; |
| NumArgsInPartiallySubstitutedPack = 0; |
| } |
| |
| /// Retrieve the partially-substitued template parameter pack. |
| /// |
| /// If there is no partially-substituted parameter pack, returns NULL. |
| NamedDecl * |
| getPartiallySubstitutedPack(const TemplateArgument **ExplicitArgs = nullptr, |
| unsigned *NumExplicitArgs = nullptr) const; |
| }; |
| |
| class TemplateDeclInstantiator |
| : public DeclVisitor<TemplateDeclInstantiator, Decl *> |
| { |
| Sema &SemaRef; |
| Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; |
| DeclContext *Owner; |
| const MultiLevelTemplateArgumentList &TemplateArgs; |
| Sema::LateInstantiatedAttrVec* LateAttrs = nullptr; |
| LocalInstantiationScope *StartingScope = nullptr; |
| |
| /// A list of out-of-line class template partial |
| /// specializations that will need to be instantiated after the |
| /// enclosing class's instantiation is complete. |
| SmallVector<std::pair<ClassTemplateDecl *, |
| ClassTemplatePartialSpecializationDecl *>, 4> |
| OutOfLinePartialSpecs; |
| |
| /// A list of out-of-line variable template partial |
| /// specializations that will need to be instantiated after the |
| /// enclosing variable's instantiation is complete. |
| /// FIXME: Verify that this is needed. |
| SmallVector< |
| std::pair<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>, 4> |
| OutOfLineVarPartialSpecs; |
| |
| public: |
| TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, |
| const MultiLevelTemplateArgumentList &TemplateArgs) |
| : SemaRef(SemaRef), |
| SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex), |
| Owner(Owner), TemplateArgs(TemplateArgs) {} |
| |
| // Define all the decl visitors using DeclNodes.inc |
| #define DECL(DERIVED, BASE) \ |
| Decl *Visit ## DERIVED ## Decl(DERIVED ## Decl *D); |
| #define ABSTRACT_DECL(DECL) |
| |
| // Decls which never appear inside a class or function. |
| #define OBJCCONTAINER(DERIVED, BASE) |
| #define FILESCOPEASM(DERIVED, BASE) |
| #define IMPORT(DERIVED, BASE) |
| #define EXPORT(DERIVED, BASE) |
| #define LINKAGESPEC(DERIVED, BASE) |
| #define OBJCCOMPATIBLEALIAS(DERIVED, BASE) |
| #define OBJCMETHOD(DERIVED, BASE) |
| #define OBJCTYPEPARAM(DERIVED, BASE) |
| #define OBJCIVAR(DERIVED, BASE) |
| #define OBJCPROPERTY(DERIVED, BASE) |
| #define OBJCPROPERTYIMPL(DERIVED, BASE) |
| #define EMPTY(DERIVED, BASE) |
| |
| // Decls which use special-case instantiation code. |
| #define BLOCK(DERIVED, BASE) |
| #define CAPTURED(DERIVED, BASE) |
| #define IMPLICITPARAM(DERIVED, BASE) |
| |
| #include "clang/AST/DeclNodes.inc" |
| |
| // A few supplemental visitor functions. |
| Decl *VisitCXXMethodDecl(CXXMethodDecl *D, |
| TemplateParameterList *TemplateParams, |
| Optional<const ASTTemplateArgumentListInfo *> |
| ClassScopeSpecializationArgs = llvm::None); |
| Decl *VisitFunctionDecl(FunctionDecl *D, |
| TemplateParameterList *TemplateParams); |
| Decl *VisitDecl(Decl *D); |
| Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate, |
| ArrayRef<BindingDecl *> *Bindings = nullptr); |
| |
| // Enable late instantiation of attributes. Late instantiated attributes |
| // will be stored in LA. |
| void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) { |
| LateAttrs = LA; |
| StartingScope = SemaRef.CurrentInstantiationScope; |
| } |
| |
| // Disable late instantiation of attributes. |
| void disableLateAttributeInstantiation() { |
| LateAttrs = nullptr; |
| StartingScope = nullptr; |
| } |
| |
| LocalInstantiationScope *getStartingScope() const { return StartingScope; } |
| |
| using delayed_partial_spec_iterator = SmallVectorImpl<std::pair< |
| ClassTemplateDecl *, ClassTemplatePartialSpecializationDecl *>>::iterator; |
| |
| using delayed_var_partial_spec_iterator = SmallVectorImpl<std::pair< |
| VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>>::iterator; |
| |
| /// Return an iterator to the beginning of the set of |
| /// "delayed" partial specializations, which must be passed to |
| /// InstantiateClassTemplatePartialSpecialization once the class |
| /// definition has been completed. |
| delayed_partial_spec_iterator delayed_partial_spec_begin() { |
| return OutOfLinePartialSpecs.begin(); |
| } |
| |
| delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() { |
| return OutOfLineVarPartialSpecs.begin(); |
| } |
| |
| /// Return an iterator to the end of the set of |
| /// "delayed" partial specializations, which must be passed to |
| /// InstantiateClassTemplatePartialSpecialization once the class |
| /// definition has been completed. |
| delayed_partial_spec_iterator delayed_partial_spec_end() { |
| return OutOfLinePartialSpecs.end(); |
| } |
| |
| delayed_var_partial_spec_iterator delayed_var_partial_spec_end() { |
| return OutOfLineVarPartialSpecs.end(); |
| } |
| |
| // Helper functions for instantiating methods. |
| TypeSourceInfo *SubstFunctionType(FunctionDecl *D, |
| SmallVectorImpl<ParmVarDecl *> &Params); |
| bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); |
| bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); |
| |
| TemplateParameterList * |
| SubstTemplateParams(TemplateParameterList *List); |
| |
| bool SubstQualifier(const DeclaratorDecl *OldDecl, |
| DeclaratorDecl *NewDecl); |
| bool SubstQualifier(const TagDecl *OldDecl, |
| TagDecl *NewDecl); |
| |
| Decl *VisitVarTemplateSpecializationDecl( |
| VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos, |
| const TemplateArgumentListInfo &TemplateArgsInfo, |
| ArrayRef<TemplateArgument> Converted, |
| VarTemplateSpecializationDecl *PrevDecl = nullptr); |
| |
| Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); |
| ClassTemplatePartialSpecializationDecl * |
| InstantiateClassTemplatePartialSpecialization( |
| ClassTemplateDecl *ClassTemplate, |
| ClassTemplatePartialSpecializationDecl *PartialSpec); |
| VarTemplatePartialSpecializationDecl * |
| InstantiateVarTemplatePartialSpecialization( |
| VarTemplateDecl *VarTemplate, |
| VarTemplatePartialSpecializationDecl *PartialSpec); |
| void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); |
| |
| private: |
| template<typename T> |
| Decl *instantiateUnresolvedUsingDecl(T *D, |
| bool InstantiatingPackElement = false); |
| }; |
| |
| } // namespace clang |
| |
| #endif // LLVM_CLANG_SEMA_TEMPLATE_H |