| //===------- SemaTemplate.h - C++ Templates ---------------------*- C++ -*-===/ |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| //===----------------------------------------------------------------------===/ |
| // |
| // 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 "llvm/ADT/SmallVector.h" |
| #include <cassert> |
| |
| namespace clang { |
| /// \brief 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 { |
| public: |
| typedef std::pair<const TemplateArgument *, unsigned> ArgList; |
| |
| private: |
| /// \brief The template argument lists, stored from the innermost template |
| /// argument list (first) to the outermost template argument list (last). |
| llvm::SmallVector<ArgList, 4> TemplateArgumentLists; |
| |
| public: |
| /// \brief Construct an empty set of template argument lists. |
| MultiLevelTemplateArgumentList() { } |
| |
| /// \brief Construct a single-level template argument list. |
| explicit |
| MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { |
| addOuterTemplateArguments(&TemplateArgs); |
| } |
| |
| /// \brief Determine the number of levels in this template argument |
| /// list. |
| unsigned getNumLevels() const { return TemplateArgumentLists.size(); } |
| |
| /// \brief Retrieve the template argument at a given depth and index. |
| const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { |
| assert(Depth < TemplateArgumentLists.size()); |
| assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second); |
| return TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index]; |
| } |
| |
| /// \brief 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 < TemplateArgumentLists.size()); |
| |
| if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].second) |
| return false; |
| |
| return !(*this)(Depth, Index).isNull(); |
| } |
| |
| /// \brief Add a new outermost level to the multi-level template argument |
| /// list. |
| void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { |
| TemplateArgumentLists.push_back( |
| ArgList(TemplateArgs->getFlatArgumentList(), |
| TemplateArgs->flat_size())); |
| } |
| |
| /// \brief Add a new outmost level to the multi-level template argument |
| /// list. |
| void addOuterTemplateArguments(const TemplateArgument *Args, |
| unsigned NumArgs) { |
| TemplateArgumentLists.push_back(ArgList(Args, NumArgs)); |
| } |
| |
| /// \brief Retrieve the innermost template argument list. |
| const ArgList &getInnermost() const { |
| return TemplateArgumentLists.front(); |
| } |
| }; |
| |
| /// \brief The context in which partial ordering of function templates occurs. |
| enum TPOC { |
| /// \brief Partial ordering of function templates for a function call. |
| TPOC_Call, |
| /// \brief Partial ordering of function templates for a call to a |
| /// conversion function. |
| TPOC_Conversion, |
| /// \brief 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; } |
| }; |
| |
| /// \brief Captures a template argument whose value has been deduced |
| /// via c++ template argument deduction. |
| class DeducedTemplateArgument : public TemplateArgument { |
| /// \brief For a non-type template argument, whether the value was |
| /// deduced from an array bound. |
| bool DeducedFromArrayBound; |
| |
| public: |
| DeducedTemplateArgument() |
| : TemplateArgument(), DeducedFromArrayBound(false) { } |
| |
| DeducedTemplateArgument(const TemplateArgument &Arg, |
| bool DeducedFromArrayBound = false) |
| : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { } |
| |
| /// \brief Construct an integral non-type template argument that |
| /// has been deduced, possible from an array bound. |
| DeducedTemplateArgument(const llvm::APSInt &Value, |
| QualType ValueType, |
| bool DeducedFromArrayBound) |
| : TemplateArgument(Value, ValueType), |
| DeducedFromArrayBound(DeducedFromArrayBound) { } |
| |
| /// \brief For a non-type template argument, determine whether the |
| /// template argument was deduced from an array bound. |
| bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } |
| |
| /// \brief Specify whether the given non-type template argument |
| /// was deduced from an array bound. |
| void setDeducedFromArrayBound(bool Deduced) { |
| DeducedFromArrayBound = Deduced; |
| } |
| }; |
| |
| /// \brief 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 { |
| /// \brief Reference to the semantic analysis that is performing |
| /// this template instantiation. |
| Sema &SemaRef; |
| |
| /// \brief 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'. |
| llvm::DenseMap<const Decl *, Decl *> LocalDecls; |
| |
| /// \brief The outer scope, which contains local variable |
| /// definitions from some other instantiation (that may not be |
| /// relevant to this particular scope). |
| LocalInstantiationScope *Outer; |
| |
| /// \brief Whether we have already exited this scope. |
| bool Exited; |
| |
| /// \brief Whether to combine this scope with the outer scope, such that |
| /// lookup will search our outer scope. |
| bool CombineWithOuterScope; |
| |
| // This class is non-copyable |
| LocalInstantiationScope(const LocalInstantiationScope &); |
| LocalInstantiationScope &operator=(const LocalInstantiationScope &); |
| |
| public: |
| LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) |
| : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), |
| Exited(false), CombineWithOuterScope(CombineWithOuterScope) |
| { |
| SemaRef.CurrentInstantiationScope = this; |
| } |
| |
| ~LocalInstantiationScope() { |
| Exit(); |
| } |
| |
| /// \brief Exit this local instantiation scope early. |
| void Exit() { |
| if (Exited) |
| return; |
| |
| SemaRef.CurrentInstantiationScope = Outer; |
| Exited = true; |
| } |
| |
| Decl *getInstantiationOf(const Decl *D); |
| |
| VarDecl *getInstantiationOf(const VarDecl *Var) { |
| return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var))); |
| } |
| |
| ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) { |
| return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var))); |
| } |
| |
| NonTypeTemplateParmDecl *getInstantiationOf( |
| const NonTypeTemplateParmDecl *Var) { |
| return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); |
| } |
| |
| void InstantiatedLocal(const Decl *D, Decl *Inst); |
| }; |
| } |
| |
| #endif // LLVM_CLANG_SEMA_TEMPLATE_H |