From: Douglas Gregor Date: Tue, 4 Aug 2009 16:50:30 +0000 (+0000) Subject: Refactor template instantiation for types into a generic tree X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=577f75a7498e9e2536434da0ef0da0eea390d18b;p=clang Refactor template instantiation for types into a generic tree transformation template (TreeTransform) that handles the transformation and reconstruction of AST nodes. Template instantiation for types is a (relatively small) customization of the generic tree transformation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78071 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 34648685ab..c557133eac 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -78,6 +78,9 @@ public: explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } + /// \brief Determine whether this template name is NULL. + bool isNull() const { return Storage.isNull(); } + /// \brief Retrieve the the underlying template declaration that /// this template name refers to, if known. /// diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1bcc8c37ec..32d6069d8d 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1,12 +1,10 @@ //===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/ - // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. //===----------------------------------------------------------------------===/ - // // This file implements semantic analysis for C++ templates. //===----------------------------------------------------------------------===/ diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index ae16c7124c..a995181d01 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===/ #include "Sema.h" +#include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" @@ -285,365 +286,95 @@ bool Sema::isSFINAEContext() const { // Template Instantiation for Types //===----------------------------------------------------------------------===/ namespace { - class VISIBILITY_HIDDEN TemplateTypeInstantiator { - Sema &SemaRef; + class VISIBILITY_HIDDEN TemplateInstantiator + : public TreeTransform + { const TemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; public: - TemplateTypeInstantiator(Sema &SemaRef, - const TemplateArgumentList &TemplateArgs, - SourceLocation Loc, - DeclarationName Entity) - : SemaRef(SemaRef), TemplateArgs(TemplateArgs), - Loc(Loc), Entity(Entity) { } - - QualType operator()(QualType T) const { return Instantiate(T); } + TemplateInstantiator(Sema &SemaRef, + const TemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity) + : TreeTransform(SemaRef), TemplateArgs(TemplateArgs), + Loc(Loc), Entity(Entity) { } + + /// \brief Determine whether the given type \p T has already been + /// transformed. + /// + /// For the purposes of template instantiation, a type has already been + /// transformed if it is NULL or if it is not dependent. + bool AlreadyTransformed(QualType T) { + return T.isNull() || !T->isDependentType(); + } + + /// \brief Returns the location of the entity being instantiated, if known. + SourceLocation getBaseLocation() { return Loc; } - QualType Instantiate(QualType T) const; - - // Declare instantiate functions for each type. -#define TYPE(Class, Base) \ - QualType Instantiate##Class##Type(const Class##Type *T) const; -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - }; -} - -QualType -TemplateTypeInstantiator::InstantiateExtQualType(const ExtQualType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ExtQualType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiateBuiltinType(const BuiltinType *T) const { - assert(false && "Builtin types are not dependent and cannot be instantiated"); - return QualType(T, 0); -} - -QualType -TemplateTypeInstantiator:: -InstantiateFixedWidthIntType(const FixedWidthIntType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate FixedWidthIntType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiateComplexType(const ComplexType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ComplexType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiatePointerType(const PointerType *T) const { - QualType PointeeType = Instantiate(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - return SemaRef.BuildPointerType(PointeeType, 0, Loc, Entity); -} - -QualType -TemplateTypeInstantiator::InstantiateBlockPointerType( - const BlockPointerType *T) const { - QualType PointeeType = Instantiate(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - return SemaRef.BuildBlockPointerType(PointeeType, 0, Loc, Entity); -} - -QualType -TemplateTypeInstantiator::InstantiateLValueReferenceType( - const LValueReferenceType *T) const { - QualType ReferentType = Instantiate(T->getPointeeType()); - if (ReferentType.isNull()) - return QualType(); - - return SemaRef.BuildReferenceType(ReferentType, true, 0, Loc, Entity); -} - -QualType -TemplateTypeInstantiator::InstantiateRValueReferenceType( - const RValueReferenceType *T) const { - QualType ReferentType = Instantiate(T->getPointeeType()); - if (ReferentType.isNull()) - return QualType(); - - return SemaRef.BuildReferenceType(ReferentType, false, 0, Loc, Entity); -} - -QualType -TemplateTypeInstantiator:: -InstantiateMemberPointerType(const MemberPointerType *T) const { - QualType PointeeType = Instantiate(T->getPointeeType()); - if (PointeeType.isNull()) - return QualType(); - - QualType ClassType = Instantiate(QualType(T->getClass(), 0)); - if (ClassType.isNull()) - return QualType(); - - return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, Loc, - Entity); -} + /// \brief Returns the name of the entity being instantiated, if any. + DeclarationName getBaseEntity() { return Entity; } + + /// \brief Transforms an expression by instantiating it with the given + /// template arguments. + Sema::OwningExprResult TransformExpr(Expr *E); -QualType -TemplateTypeInstantiator:: -InstantiateConstantArrayType(const ConstantArrayType *T) const { - QualType ElementType = Instantiate(T->getElementType()); - if (ElementType.isNull()) - return ElementType; - - // Build a temporary integer literal to specify the size for - // BuildArrayType. Since we have already checked the size as part of - // creating the dependent array type in the first place, we know - // there aren't any errors. However, we do need to determine what - // C++ type to give the size expression. - llvm::APInt Size = T->getSize(); - QualType Types[] = { - SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, - SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, - SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty + /// \brief Transform the given declaration by instantiating a reference to + /// this declaration. + Decl *TransformDecl(Decl *D); + + /// \brief Transform the given nested-name-specifier by instantiating it. + NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range); + + /// \brief Transform the given template name by instantiating it. + TemplateName TransformTemplateName(TemplateName Template); + + /// \brief Transform the given template argument by instantiating it. + TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); + + /// \brief Transforms a template type parameter type by performing + /// substitution of the corresponding template type argument. + QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T); }; - const unsigned NumTypes = sizeof(Types) / sizeof(QualType); - QualType SizeType; - for (unsigned I = 0; I != NumTypes; ++I) - if (Size.getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { - SizeType = Types[I]; - break; - } - - if (SizeType.isNull()) - SizeType = SemaRef.Context.getFixedWidthIntType(Size.getBitWidth(), false); - - IntegerLiteral ArraySize(Size, SizeType, Loc); - return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), - &ArraySize, T->getIndexTypeQualifier(), - SourceRange(), // FIXME: provide proper range? - Entity); -} - -QualType -TemplateTypeInstantiator::InstantiateConstantArrayWithExprType -(const ConstantArrayWithExprType *T) const { - return InstantiateConstantArrayType(T); -} - -QualType -TemplateTypeInstantiator::InstantiateConstantArrayWithoutExprType -(const ConstantArrayWithoutExprType *T) const { - return InstantiateConstantArrayType(T); -} - -QualType -TemplateTypeInstantiator:: -InstantiateIncompleteArrayType(const IncompleteArrayType *T) const { - QualType ElementType = Instantiate(T->getElementType()); - if (ElementType.isNull()) - return ElementType; - - return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), - 0, T->getIndexTypeQualifier(), - SourceRange(), // FIXME: provide proper range? - Entity); -} - -QualType -TemplateTypeInstantiator:: -InstantiateVariableArrayType(const VariableArrayType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate VariableArrayType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator:: -InstantiateDependentSizedArrayType(const DependentSizedArrayType *T) const { - Expr *ArraySize = T->getSizeExpr(); - assert(ArraySize->isValueDependent() && - "dependent sized array types must have value dependent size expr"); - - // Instantiate the element type if needed - QualType ElementType = T->getElementType(); - if (ElementType->isDependentType()) { - ElementType = Instantiate(ElementType); - if (ElementType.isNull()) - return QualType(); - } - - // Instantiate the size expression - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - Sema::OwningExprResult InstantiatedArraySize = - SemaRef.InstantiateExpr(ArraySize, TemplateArgs); - if (InstantiatedArraySize.isInvalid()) - return QualType(); - - return SemaRef.BuildArrayType(ElementType, T->getSizeModifier(), - InstantiatedArraySize.takeAs(), - T->getIndexTypeQualifier(), - SourceRange(), // FIXME: provide proper range? - Entity); -} - -QualType -TemplateTypeInstantiator:: -InstantiateDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) const { - - // Instantiate the element type if needed. - QualType ElementType = T->getElementType(); - if (ElementType->isDependentType()) { - ElementType = Instantiate(ElementType); - if (ElementType.isNull()) - return QualType(); - } - - // The expression in a dependent-sized extended vector type is not - // potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - - // Instantiate the size expression. - const Expr *SizeExpr = T->getSizeExpr(); - Sema::OwningExprResult InstantiatedArraySize = - SemaRef.InstantiateExpr(const_cast(SizeExpr), TemplateArgs); - if (InstantiatedArraySize.isInvalid()) - return QualType(); - - return SemaRef.BuildExtVectorType(ElementType, - SemaRef.Owned( - InstantiatedArraySize.takeAs()), - T->getAttributeLoc()); } -QualType -TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate VectorType yet"); - return QualType(); +Sema::OwningExprResult TemplateInstantiator::TransformExpr(Expr *E) { + return getSema().InstantiateExpr(E, TemplateArgs); } -QualType -TemplateTypeInstantiator::InstantiateExtVectorType( - const ExtVectorType *T) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ExtVectorType yet"); - return QualType(); -} - -QualType -TemplateTypeInstantiator:: -InstantiateFunctionProtoType(const FunctionProtoType *T) const { - QualType ResultType = Instantiate(T->getResultType()); - if (ResultType.isNull()) - return ResultType; - - llvm::SmallVector ParamTypes; - for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), - ParamEnd = T->arg_type_end(); - Param != ParamEnd; ++Param) { - QualType P = Instantiate(*Param); - if (P.isNull()) - return P; - - ParamTypes.push_back(P); - } - - return SemaRef.BuildFunctionType(ResultType, ParamTypes.data(), - ParamTypes.size(), - T->isVariadic(), T->getTypeQuals(), - Loc, Entity); -} - -QualType -TemplateTypeInstantiator:: -InstantiateFunctionNoProtoType(const FunctionNoProtoType *T) const { - assert(false && "Functions without prototypes cannot be dependent."); - return QualType(); -} - -QualType -TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T) const { - TypedefDecl *Typedef - = cast_or_null( - SemaRef.InstantiateCurrentDeclRef(T->getDecl())); - if (!Typedef) - return QualType(); - - return SemaRef.Context.getTypeDeclType(Typedef); +Decl *TemplateInstantiator::TransformDecl(Decl *D) { + return SemaRef.InstantiateCurrentDeclRef(cast_or_null(D)); } -QualType -TemplateTypeInstantiator::InstantiateTypeOfExprType( - const TypeOfExprType *T) const { - // The expression in a typeof is not potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); - - Sema::OwningExprResult E - = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs); - if (E.isInvalid()) - return QualType(); - - return SemaRef.BuildTypeofExprType(E.takeAs()); -} - -QualType -TemplateTypeInstantiator::InstantiateTypeOfType(const TypeOfType *T) const { - QualType Underlying = Instantiate(T->getUnderlyingType()); - if (Underlying.isNull()) - return QualType(); - - return SemaRef.Context.getTypeOfType(Underlying); -} - -QualType -TemplateTypeInstantiator::InstantiateDecltypeType(const DecltypeType *T) const { - // C++0x [dcl.type.simple]p4: - // The operand of the decltype specifier is an unevaluated operand. - EnterExpressionEvaluationContext Unevaluated(SemaRef, - Action::Unevaluated); - - Sema::OwningExprResult E - = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs); - - if (E.isInvalid()) - return QualType(); - - return SemaRef.BuildDecltypeType(E.takeAs()); +NestedNameSpecifier * +TemplateInstantiator::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range) { + return getSema().InstantiateNestedNameSpecifier(NNS, Range, TemplateArgs); } -QualType -TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T) const { - RecordDecl *Record - = cast_or_null(SemaRef.InstantiateCurrentDeclRef(T->getDecl())); - if (!Record) - return QualType(); - - return SemaRef.Context.getTypeDeclType(Record); +TemplateName +TemplateInstantiator::TransformTemplateName(TemplateName Template) { + return getSema().InstantiateTemplateName(Template, /*FIXME*/Loc, + TemplateArgs); } -QualType -TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T) const { - EnumDecl *Enum - = cast_or_null(SemaRef.InstantiateCurrentDeclRef(T->getDecl())); - if (!Enum) - return QualType(); - - return SemaRef.Context.getTypeDeclType(Enum); +TemplateArgument +TemplateInstantiator::TransformTemplateArgument(const TemplateArgument &Arg) { + return getSema().Instantiate(Arg, TemplateArgs); } QualType -TemplateTypeInstantiator:: -InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const { +TemplateInstantiator::TransformTemplateTypeParmType( + const TemplateTypeParmType *T) { if (T->getDepth() == 0) { // Replace the template type parameter with its corresponding // template argument. + // FIXME: When dealing with member templates, we might end up with multiple + /// levels of template arguments that we're substituting into concurrently. + // If the corresponding template argument is NULL or doesn't exist, it's // because we are performing instantiation from explicitly-specified // template arguments in a function template class, but there were some @@ -661,112 +392,10 @@ InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const { // the template parameter list of a member template inside the // template we are instantiating). Create a new template type // parameter with the template "level" reduced by one. - return SemaRef.Context.getTemplateTypeParmType(T->getDepth() - 1, - T->getIndex(), - T->isParameterPack(), - T->getName()); -} - -QualType -TemplateTypeInstantiator:: -InstantiateTemplateSpecializationType( - const TemplateSpecializationType *T) const { - llvm::SmallVector InstantiatedTemplateArgs; - InstantiatedTemplateArgs.reserve(T->getNumArgs()); - for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); - Arg != ArgEnd; ++Arg) { - TemplateArgument InstArg = SemaRef.Instantiate(*Arg, TemplateArgs); - if (InstArg.isNull()) - return QualType(); - - InstantiatedTemplateArgs.push_back(InstArg); - } - - // FIXME: We're missing the locations of the template name, '<', and '>'. - - TemplateName Name = SemaRef.InstantiateTemplateName(T->getTemplateName(), - Loc, - TemplateArgs); - - return SemaRef.CheckTemplateIdType(Name, Loc, SourceLocation(), - InstantiatedTemplateArgs.data(), - InstantiatedTemplateArgs.size(), - SourceLocation()); -} - -QualType -TemplateTypeInstantiator:: -InstantiateQualifiedNameType(const QualifiedNameType *T) const { - // When we instantiated a qualified name type, there's no point in - // keeping the qualification around in the instantiated result. So, - // just instantiate the named type. - return (*this)(T->getNamedType()); -} - -QualType -TemplateTypeInstantiator:: -InstantiateTypenameType(const TypenameType *T) const { - if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { - // When the typename type refers to a template-id, the template-id - // is dependent and has enough information to instantiate the - // result of the typename type. Since we don't care about keeping - // the spelling of the typename type in template instantiations, - // we just instantiate the template-id. - return InstantiateTemplateSpecializationType(TemplateId); - } - - NestedNameSpecifier *NNS - = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(), - SourceRange(Loc), - TemplateArgs); - if (!NNS) - return QualType(); - - return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc)); -} - -QualType -TemplateTypeInstantiator:: -InstantiateObjCObjectPointerType(const ObjCObjectPointerType *T) const { - assert(false && "Objective-C types cannot be dependent"); - return QualType(); -} - -QualType -TemplateTypeInstantiator:: -InstantiateObjCInterfaceType(const ObjCInterfaceType *T) const { - assert(false && "Objective-C types cannot be dependent"); - return QualType(); -} - -/// \brief The actual implementation of Sema::InstantiateType(). -QualType TemplateTypeInstantiator::Instantiate(QualType T) const { - // If T is not a dependent type, there is nothing to do. - if (!T->isDependentType()) - return T; - - QualType Result; - switch (T->getTypeClass()) { -#define TYPE(Class, Base) \ - case Type::Class: \ - Result = Instantiate##Class##Type(cast(T.getTypePtr())); \ - break; -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - } - - // C++ [dcl.ref]p1: - // [...] Cv-qualified references are ill-formed except when - // the cv-qualifiers are introduced through the use of a - // typedef (7.1.3) or of a template type argument (14.3), in - // which case the cv-qualifiers are ignored. - // - // The same rule applies to function types. - // FIXME: what about address-space and Objective-C GC qualifiers? - if (!Result.isNull() && T.getCVRQualifiers() && - !Result->isFunctionType() && !Result->isReferenceType()) - Result = Result.getWithAdditionalQualifiers(T.getCVRQualifiers()); - return Result; + return getSema().Context.getTemplateTypeParmType(T->getDepth() - 1, + T->getIndex(), + T->isParameterPack(), + T->getName()); } /// \brief Instantiate the type T with a given set of template arguments. @@ -806,8 +435,8 @@ QualType Sema::InstantiateType(QualType T, if (!T->isDependentType()) return T; - TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); - return Instantiator(T); + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); + return Instantiator.TransformType(T); } /// \brief Instantiate the base class specifiers of the given class diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h new file mode 100644 index 0000000000..622f7b44cd --- /dev/null +++ b/lib/Sema/TreeTransform.h @@ -0,0 +1,1135 @@ +//===------- TreeTransform.h - Semantic Tree Transformation ---------------===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements a semantic tree transformation that takes a given +// AST and rebuilds it, possibly transforming some nodes in the process. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H +#define LLVM_CLANG_SEMA_TREETRANSFORM_H + +#include "Sema.h" +#include + +namespace clang { + +/// \brief A semantic tree transformation that allows one to transform one +/// abstract syntax tree into another. +/// +/// A new tree transformation is defined by creating a new subclass \c X of +/// \c TreeTransform and then overriding certain operations to provide +/// behavior specific to that transformation. For example, template +/// instantiation is implemented as a tree transformation where the +/// transformation of TemplateTypeParmType nodes involves substituting the +/// template arguments for their corresponding template parameters; a similar +/// transformation is performed for non-type template parameters and +/// template template parameters. +/// +/// This tree-transformation template uses static polymorphism to allow +/// subclasses to customize any of its operations. Thus, a subclass can +/// override any of the transformation or rebuild operators by providing an +/// operation with the same signature as the default implementation. The +/// overridding function should not be virtual. +/// +/// Semantic tree transformations are split into two stages, either of which +/// can be replaced by a subclass. The "transform" step transforms an AST node +/// or the parts of an AST node using the various transformation functions, +/// then passes the pieces on to the "rebuild" step, which constructs a new AST +/// node of the appropriate kind from the pieces. The default transformation +/// routines recursively transform the operands to composite AST nodes (e.g., +/// the pointee type of a PointerType node) and, if any of those operand nodes +/// were changed by the transformation, invokes the rebuild operation to create +/// a new AST node. +/// +/// Subclasses can customize the transformation at various levels. The +/// most course-grained transformations involve replacing TransformType(), +/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(), +/// TransformTemplateName(), or TransformTemplateArgument() with entirely +/// new implementations. +/// +/// For more fine-grained transformations, subclasses can replace any of the +/// \c TransformXXX functions (where XXX is the name of an AST node, e.g., +/// PointerType) to alter the transformation. As mentioned previously, +/// replacing TransformTemplateTypeParmType() allows template instantiation +/// to substitute template arguments for their corresponding template +/// parameters. Additionally, subclasses can override the \c RebuildXXX +/// functions to control how AST nodes are rebuilt when their operands change. +/// By default, \c TreeTransform will invoke semantic analysis to rebuild +/// AST nodes. However, certain other tree transformations (e.g, cloning) may +/// be able to use more efficient rebuild steps. +/// +/// There are a handful of other functions that can be overridden, allowing one +/// to avoid traversing nodes that don't need any transformation +/// (\c AlreadyTransformed()), force rebuilding AST nodes even when their +/// operands have not changed (\c AlwaysRebuild()), and customize the +/// default locations and entity names used for type-checking +/// (\c getBaseLocation(), \c getBaseEntity()). +/// +/// FIXME: In the future, TreeTransform will support transformation of +/// statements and expressions as well as types. +template +class TreeTransform { +protected: + Sema &SemaRef; + +public: + /// \brief Initializes a new tree transformer. + TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } + + /// \brief Retrieves a reference to the derived class. + Derived &getDerived() { return static_cast(*this); } + + /// \brief Retrieves a reference to the derived class. + const Derived &getDerived() const { + return static_cast(*this); + } + + /// \brief Retrieves a reference to the semantic analysis object used for + /// this tree transform. + Sema &getSema() const { return SemaRef; } + + /// \brief Whether the transformation should always rebuild AST nodes, even + /// if none of the children have changed. + /// + /// Subclasses may override this function to specify when the transformation + /// should rebuild all AST nodes. + bool AlwaysRebuild() { return false; } + + /// \brief Returns the location of the entity being transformed, if that + /// information was not available elsewhere in the AST. + /// + /// By default, returns no source-location information. Subclasses can + /// provide an alternative implementation that provides better location + /// information. + SourceLocation getBaseLocation() { return SourceLocation(); } + + /// \brief Returns the name of the entity being transformed, if that + /// information was not available elsewhere in the AST. + /// + /// By default, returns an empty name. Subclasses can provide an alternative + /// implementation with a more precise name. + DeclarationName getBaseEntity() { return DeclarationName(); } + + /// \brief Determine whether the given type \p T has already been + /// transformed. + /// + /// Subclasses can provide an alternative implementation of this routine + /// to short-circuit evaluation when it is known that a given type will + /// not change. For example, template instantiation need not traverse + /// non-dependent types. + bool AlreadyTransformed(QualType T) { + return T.isNull(); + } + + /// \brief Transforms the given type into another type. + /// + /// By default, this routine transforms a type by delegating to the + /// appropriate TransformXXXType to build a new type, then applying + /// the qualifiers on \p T to the resulting type with AddTypeQualifiers. + /// Subclasses may override this function (to take over all type + /// transformations), some set of the TransformXXXType functions, or + /// the AddTypeQualifiers function to alter the transformation. + /// + /// \returns the transformed type. + QualType TransformType(QualType T); + + /// \brief Transform the given type by adding the given set of qualifiers + /// and returning the result. + /// + /// FIXME: By default, this routine adds type qualifiers only to types that + /// can have qualifiers, and silently suppresses those qualifiers that are + /// not permitted (e.g., qualifiers on reference or function types). This + /// is the right thing for template instantiation, but probably not for + /// other clients. + QualType AddTypeQualifiers(QualType T, unsigned CVRQualifiers); + + /// \brief Transform the given expression. + /// + /// FIXME: At the moment, subclasses must override this. + Sema::OwningExprResult TransformExpr(Expr *E); + + /// \brief Transform the given declaration, which is referenced from a type + /// or expression. + /// + /// Subclasses must override this. + Decl *TransformDecl(Decl *D); + + /// \brief Transform the given nested-name-specifier. + /// + /// Subclasses must override this. + NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range); + + /// \brief Transform the given template name. + /// + /// FIXME: At the moment, subclasses must override this. + TemplateName TransformTemplateName(TemplateName Template); + + /// \brief Transform the given template argument. + /// + /// FIXME: At the moment, subclasses must override this. + TemplateArgument TransformTemplateArgument(const TemplateArgument &Arg); + +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + QualType Transform##CLASS##Type(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + /// \brief Build a new pointer type given its pointee type. + /// + /// By default, performs semantic analysis when building the pointer type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildPointerType(QualType PointeeType); + + /// \brief Build a new block pointer type given its pointee type. + /// + /// By default, performs semantic analysis when building the block pointer + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildBlockPointerType(QualType PointeeType); + + /// \brief Build a new lvalue reference type given the type it references. + /// + /// By default, performs semantic analysis when building the lvalue reference + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildLValueReferenceType(QualType ReferentType); + + /// \brief Build a new rvalue reference type given the type it references. + /// + /// By default, performs semantic analysis when building the rvalue reference + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildRValueReferenceType(QualType ReferentType); + + /// \brief Build a new member pointer type given the pointee type and the + /// class type it refers into. + /// + /// By default, performs semantic analysis when building the member pointer + /// type. Subclasses may override this routine to provide different behavior. + QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType); + + /// \brief Build a new array type given the element type, size + /// modifier, size of the array (if known), size expression, and index type + /// qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + /// Also by default, all of the other Rebuild*Array + QualType RebuildArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt *Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new constant array type given the element type, size + /// modifier, (known) size of the array, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildConstantArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals); + + /// \brief Build a new constant array type given the element type, size + /// modifier, (known) size of the array, size expression, and index type + /// qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildConstantArrayWithExprType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new constant array type given the element type, size + /// modifier, (known) size of the array, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildConstantArrayWithoutExprType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals); + + /// \brief Build a new incomplete array type given the element type, size + /// modifier, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildIncompleteArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + unsigned IndexTypeQuals); + + /// \brief Build a new variable-length array type given the element type, + /// size modifier, size expression, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildVariableArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + Sema::ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new dependent-sized array type given the element type, + /// size modifier, size expression, and index type qualifiers. + /// + /// By default, performs semantic analysis when building the array type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDependentSizedArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + Sema::ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange); + + /// \brief Build a new vector type given the element type and + /// number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildVectorType(QualType ElementType, unsigned NumElements); + + /// \brief Build a new extended vector type given the element type and + /// number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildExtVectorType(QualType ElementType, unsigned NumElements, + SourceLocation AttributeLoc); + + /// \brief Build a new potentially dependently-sized extended vector type + /// given the element type and number of elements. + /// + /// By default, performs semantic analysis when building the vector type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDependentSizedExtVectorType(QualType ElementType, + Sema::ExprArg SizeExpr, + SourceLocation AttributeLoc); + + /// \brief Build a new function type. + /// + /// By default, performs semantic analysis when building the function type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildFunctionProtoType(QualType T, + QualType *ParamTypes, + unsigned NumParamTypes, + bool Variadic, unsigned Quals); + + /// \brief Build a new typedef type. + QualType RebuildTypedefType(TypedefDecl *Typedef) { + return SemaRef.Context.getTypeDeclType(Typedef); + } + + /// \brief Build a new class/struct/union type. + QualType RebuildRecordType(RecordDecl *Record) { + return SemaRef.Context.getTypeDeclType(Record); + } + + /// \brief Build a new Enum type. + QualType RebuildEnumType(EnumDecl *Enum) { + return SemaRef.Context.getTypeDeclType(Enum); + } + + /// \brief Build a new typeof(expr) type. + /// + /// By default, performs semantic analysis when building the typeof type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildTypeOfExprType(Sema::ExprArg Underlying); + + /// \brief Build a new typeof(type) type. + /// + /// By default, builds a new TypeOfType with the given underlying type. + QualType RebuildTypeOfType(QualType Underlying); + + /// \brief Build a new C++0x decltype type. + /// + /// By default, performs semantic analysis when building the decltype type. + /// Subclasses may override this routine to provide different behavior. + QualType RebuildDecltypeType(Sema::ExprArg Underlying); + + /// \brief Build a new template specialization type. + /// + /// By default, performs semantic analysis when building the template + /// specialization type. Subclasses may override this routine to provide + /// different behavior. + QualType RebuildTemplateSpecializationType(TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Build a new qualified name type. + /// + /// By default, builds a new QualifiedNameType type from the + /// nested-name-specifier and the named type. Subclasses may override + /// this routine to provide different behavior. + QualType RebuildQualifiedNameType(NestedNameSpecifier *NNS, QualType Named) { + return SemaRef.Context.getQualifiedNameType(NNS, Named); + } + + /// \brief Build a new typename type that refers to a template-id. + /// + /// By default, builds a new TypenameType type from the nested-name-specifier + /// and the given type. Subclasses may override this routine to provide + /// different behavior. + QualType RebuildTypenameType(NestedNameSpecifier *NNS, QualType T) { + if (NNS->isDependent()) + return SemaRef.Context.getTypenameType(NNS, + cast(T)); + + return SemaRef.Context.getQualifiedNameType(NNS, T); + } + + /// \brief Build a new typename type that refers to an identifier. + /// + /// By default, performs semantic analysis when building the typename type + /// (or qualified name type). Subclasses may override this routine to provide + /// different behavior. + QualType RebuildTypenameType(NestedNameSpecifier *NNS, + const IdentifierInfo *Id) { + return SemaRef.CheckTypenameType(NNS, *Id, + SourceRange(getDerived().getBaseLocation())); + } +}; + +//===----------------------------------------------------------------------===// +// Type transformation +//===----------------------------------------------------------------------===// + +template +QualType TreeTransform::TransformType(QualType T) { + if (getDerived().AlreadyTransformed(T)) + return T; + + QualType Result; + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + Result = getDerived().Transform##CLASS##Type( \ + static_cast(T.getTypePtr())); \ + break; +#include "clang/AST/TypeNodes.def" + } + + if (Result.isNull() || T == Result) + return Result; + + return getDerived().AddTypeQualifiers(Result, T.getCVRQualifiers()); +} + +template +QualType +TreeTransform::AddTypeQualifiers(QualType T, unsigned CVRQualifiers) { + if (CVRQualifiers && !T->isFunctionType() && !T->isReferenceType()) + return T.getWithAdditionalQualifiers(CVRQualifiers); + + return T; +} + +template +QualType TreeTransform::TransformExtQualType(const ExtQualType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformBuiltinType(const BuiltinType *T) { + // Nothing to do + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformFixedWidthIntType( + const FixedWidthIntType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformComplexType(const ComplexType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformPointerType(const PointerType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildPointerType(PointeeType); +} + +template +QualType +TreeTransform::TransformBlockPointerType(const BlockPointerType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildBlockPointerType(PointeeType); +} + +template +QualType +TreeTransform::TransformLValueReferenceType( + const LValueReferenceType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildLValueReferenceType(PointeeType); +} + +template +QualType +TreeTransform::TransformRValueReferenceType( + const RValueReferenceType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType()) + return QualType(T, 0); + + return getDerived().RebuildRValueReferenceType(PointeeType); +} + +template +QualType +TreeTransform::TransformMemberPointerType(const MemberPointerType *T) { + QualType PointeeType = getDerived().TransformType(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + QualType ClassType = getDerived().TransformType(QualType(T->getClass(), 0)); + if (ClassType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + PointeeType == T->getPointeeType() && + ClassType == QualType(T->getClass(), 0)) + return QualType(T, 0); + + return getDerived().RebuildMemberPointerType(PointeeType, ClassType); +} + +template +QualType +TreeTransform::TransformConstantArrayType(const ConstantArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildConstantArrayType(ElementType, + T->getSizeModifier(), + T->getSize(), + T->getIndexTypeQualifier()); +} + +template +QualType +TreeTransform::TransformConstantArrayWithExprType( + const ConstantArrayWithExprType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildConstantArrayWithExprType(ElementType, + T->getSizeModifier(), + T->getSize(), + /*FIXME: Transform?*/T->getSizeExpr(), + T->getIndexTypeQualifier(), + T->getBracketsRange()); +} + +template +QualType +TreeTransform::TransformConstantArrayWithoutExprType( + const ConstantArrayWithoutExprType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildConstantArrayWithoutExprType(ElementType, + T->getSizeModifier(), + T->getSize(), + T->getIndexTypeQualifier()); +} + +template +QualType TreeTransform::TransformIncompleteArrayType( + const IncompleteArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildIncompleteArrayType(ElementType, + T->getSizeModifier(), + T->getIndexTypeQualifier()); +} + +template +QualType TreeTransform::TransformVariableArrayType( + const VariableArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) { + Size.take(); + return QualType(T, 0); + } + + return getDerived().RebuildVariableArrayType(ElementType, + T->getSizeModifier(), + move(Size), + T->getIndexTypeQualifier(), + T->getBracketsRange()); +} + +template +QualType TreeTransform::TransformDependentSizedArrayType( + const DependentSizedArrayType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) { + Size.take(); + return QualType(T, 0); + } + + return getDerived().RebuildDependentSizedArrayType(ElementType, + T->getSizeModifier(), + move(Size), + T->getIndexTypeQualifier(), + T->getBracketsRange()); +} + +template +QualType TreeTransform::TransformDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + Sema::OwningExprResult Size = getDerived().TransformExpr(T->getSizeExpr()); + if (Size.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType() && + Size.get() == T->getSizeExpr()) { + Size.take(); + return QualType(T, 0); + } + + return getDerived().RebuildDependentSizedExtVectorType(ElementType, + move(Size), + T->getAttributeLoc()); +} + +template +QualType TreeTransform::TransformVectorType(const VectorType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildVectorType(ElementType, T->getNumElements()); +} + +template +QualType +TreeTransform::TransformExtVectorType(const ExtVectorType *T) { + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + ElementType == T->getElementType()) + return QualType(T, 0); + + return getDerived().RebuildExtVectorType(ElementType, T->getNumElements(), + /*FIXME*/SourceLocation()); +} + +template +QualType TreeTransform::TransformFunctionProtoType( + const FunctionProtoType *T) { + QualType ResultType = getDerived().TransformType(T->getResultType()); + if (ResultType.isNull()) + return QualType(); + + llvm::SmallVector ParamTypes; + for (FunctionProtoType::arg_type_iterator Param = T->arg_type_begin(), + ParamEnd = T->arg_type_end(); + Param != ParamEnd; ++Param) { + QualType P = getDerived().TransformType(*Param); + if (P.isNull()) + return QualType(); + + ParamTypes.push_back(P); + } + + if (!getDerived().AlwaysRebuild() && + ResultType == T->getResultType() && + std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) + return QualType(T, 0); + + return getDerived().RebuildFunctionProtoType(ResultType, ParamTypes.data(), + ParamTypes.size(), T->isVariadic(), + T->getTypeQuals()); +} + +template +QualType TreeTransform::TransformFunctionNoProtoType( + const FunctionNoProtoType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformTypedefType(const TypedefType *T) { + TypedefDecl *Typedef + = cast_or_null(getDerived().TransformDecl(T->getDecl())); + if (!Typedef) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Typedef == T->getDecl()) + return QualType(T, 0); + + return getDerived().RebuildTypedefType(Typedef); +} + +template +QualType TreeTransform::TransformTypeOfExprType( + const TypeOfExprType *T) { + Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); + if (E.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + E.get() == T->getUnderlyingExpr()) { + E.take(); + return QualType(T, 0); + } + + return getDerived().RebuildTypeOfExprType(move(E)); +} + +template +QualType TreeTransform::TransformTypeOfType(const TypeOfType *T) { + QualType Underlying = getDerived().TransformType(T->getUnderlyingType()); + if (Underlying.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Underlying == T->getUnderlyingType()) + return QualType(T, 0); + + return getDerived().RebuildTypeOfType(Underlying); +} + +template +QualType TreeTransform::TransformDecltypeType(const DecltypeType *T) { + Sema::OwningExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); + if (E.isInvalid()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + E.get() == T->getUnderlyingExpr()) { + E.take(); + return QualType(T, 0); + } + + return getDerived().RebuildDecltypeType(move(E)); +} + +template +QualType TreeTransform::TransformRecordType(const RecordType *T) { + RecordDecl *Record + = cast_or_null(getDerived().TransformDecl(T->getDecl())); + if (!Record) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Record == T->getDecl()) + return QualType(T, 0); + + return getDerived().RebuildRecordType(Record); +} + +template +QualType TreeTransform::TransformEnumType(const EnumType *T) { + EnumDecl *Enum + = cast_or_null(getDerived().TransformDecl(T->getDecl())); + if (!Enum) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + Enum == T->getDecl()) + return QualType(T, 0); + + return getDerived().RebuildEnumType(Enum); +} + +template +QualType TreeTransform::TransformTemplateTypeParmType( + const TemplateTypeParmType *T) { + // Nothing to do + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformTemplateSpecializationType( + const TemplateSpecializationType *T) { + TemplateName Template + = getDerived().TransformTemplateName(T->getTemplateName()); + if (Template.isNull()) + return QualType(); + + llvm::SmallVector NewTemplateArgs; + NewTemplateArgs.reserve(T->getNumArgs()); + for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); + Arg != ArgEnd; ++Arg) { + TemplateArgument NewArg = getDerived().TransformTemplateArgument(*Arg); + if (NewArg.isNull()) + return QualType(); + + NewTemplateArgs.push_back(NewArg); + } + + // FIXME: early abort if all of the template arguments and such are the + // same. + + // FIXME: We're missing the locations of the template name, '<', and '>'. + return getDerived().RebuildTemplateSpecializationType(Template, + NewTemplateArgs.data(), + NewTemplateArgs.size()); +} + +template +QualType TreeTransform::TransformQualifiedNameType( + const QualifiedNameType *T) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + SourceRange()); + if (!NNS) + return QualType(); + + QualType Named = getDerived().TransformType(T->getNamedType()); + if (Named.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + NNS == T->getQualifier() && + Named == T->getNamedType()) + return QualType(T, 0); + + return getDerived().RebuildQualifiedNameType(NNS, Named); +} + +template +QualType TreeTransform::TransformTypenameType(const TypenameType *T) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), + SourceRange(getDerived().getBaseLocation())); + if (!NNS) + return QualType(); + + if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) { + QualType NewTemplateId + = getDerived().TransformType(QualType(TemplateId, 0)); + if (NewTemplateId.isNull()) + return QualType(); + + if (!getDerived().AlwaysRebuild() && + NNS == T->getQualifier() && + NewTemplateId == QualType(TemplateId, 0)) + return QualType(T, 0); + + return getDerived().RebuildTypenameType(NNS, NewTemplateId); + } + + return getDerived().RebuildTypenameType(NNS, T->getIdentifier()); +} + +template +QualType TreeTransform::TransformObjCInterfaceType( + const ObjCInterfaceType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +template +QualType TreeTransform::TransformObjCObjectPointerType( + const ObjCObjectPointerType *T) { + // FIXME: Implement + return QualType(T, 0); +} + +//===----------------------------------------------------------------------===// +// Type reconstruction +//===----------------------------------------------------------------------===// + +template +QualType TreeTransform::RebuildPointerType(QualType PointeeType) { + return SemaRef.BuildPointerType(PointeeType, 0, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template +QualType TreeTransform::RebuildBlockPointerType(QualType PointeeType) { + return SemaRef.BuildBlockPointerType(PointeeType, 0, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template +QualType +TreeTransform::RebuildLValueReferenceType(QualType ReferentType) { + return SemaRef.BuildReferenceType(ReferentType, true, 0, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template +QualType +TreeTransform::RebuildRValueReferenceType(QualType ReferentType) { + return SemaRef.BuildReferenceType(ReferentType, false, 0, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template +QualType TreeTransform::RebuildMemberPointerType(QualType PointeeType, + QualType ClassType) { + return SemaRef.BuildMemberPointerType(PointeeType, ClassType, 0, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template +QualType +TreeTransform::RebuildArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt *Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + if (SizeExpr || !Size) + return SemaRef.BuildArrayType(ElementType, SizeMod, SizeExpr, + IndexTypeQuals, BracketsRange, + getDerived().getBaseEntity()); + + QualType Types[] = { + SemaRef.Context.UnsignedCharTy, SemaRef.Context.UnsignedShortTy, + SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, + SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty + }; + const unsigned NumTypes = sizeof(Types) / sizeof(QualType); + QualType SizeType; + for (unsigned I = 0; I != NumTypes; ++I) + if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { + SizeType = Types[I]; + break; + } + + if (SizeType.isNull()) + SizeType = SemaRef.Context.getFixedWidthIntType(Size->getBitWidth(), false); + + IntegerLiteral ArraySize(*Size, SizeType, /*FIXME*/BracketsRange.getBegin()); + return SemaRef.BuildArrayType(ElementType, SizeMod, &ArraySize, + IndexTypeQuals, BracketsRange, + getDerived().getBaseEntity()); +} + +template +QualType +TreeTransform::RebuildConstantArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals) { + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, + IndexTypeQuals, SourceRange()); +} + +template +QualType +TreeTransform::RebuildConstantArrayWithExprType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + Expr *SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr, + IndexTypeQuals, BracketsRange); +} + +template +QualType +TreeTransform::RebuildConstantArrayWithoutExprType( + QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + const llvm::APInt &Size, + unsigned IndexTypeQuals) { + return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, 0, + IndexTypeQuals, SourceRange()); +} + +template +QualType +TreeTransform::RebuildIncompleteArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + unsigned IndexTypeQuals) { + return getDerived().RebuildArrayType(ElementType, SizeMod, 0, 0, + IndexTypeQuals, SourceRange()); +} + +template +QualType +TreeTransform::RebuildVariableArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + Sema::ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + return getDerived().RebuildArrayType(ElementType, SizeMod, 0, + SizeExpr.takeAs(), + IndexTypeQuals, BracketsRange); +} + +template +QualType +TreeTransform::RebuildDependentSizedArrayType(QualType ElementType, + ArrayType::ArraySizeModifier SizeMod, + Sema::ExprArg SizeExpr, + unsigned IndexTypeQuals, + SourceRange BracketsRange) { + return getDerived().RebuildArrayType(ElementType, SizeMod, 0, + SizeExpr.takeAs(), + IndexTypeQuals, BracketsRange); +} + +template +QualType TreeTransform::RebuildVectorType(QualType ElementType, + unsigned NumElements) { + // FIXME: semantic checking! + return SemaRef.Context.getVectorType(ElementType, NumElements); +} + +template +QualType TreeTransform::RebuildExtVectorType(QualType ElementType, + unsigned NumElements, + SourceLocation AttributeLoc) { + llvm::APInt numElements(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy), + NumElements, true); + IntegerLiteral *VectorSize + = new (SemaRef.Context) IntegerLiteral(numElements, SemaRef.Context.IntTy, + AttributeLoc); + return SemaRef.BuildExtVectorType(ElementType, SemaRef.Owned(VectorSize), + AttributeLoc); +} + +template +QualType +TreeTransform::RebuildDependentSizedExtVectorType(QualType ElementType, + Sema::ExprArg SizeExpr, + SourceLocation AttributeLoc) { + return SemaRef.BuildExtVectorType(ElementType, move(SizeExpr), AttributeLoc); +} + +template +QualType TreeTransform::RebuildFunctionProtoType(QualType T, + QualType *ParamTypes, + unsigned NumParamTypes, + bool Variadic, + unsigned Quals) { + return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic, + Quals, + getDerived().getBaseLocation(), + getDerived().getBaseEntity()); +} + +template +QualType TreeTransform::RebuildTypeOfExprType(Sema::ExprArg E) { + return SemaRef.BuildTypeofExprType(E.takeAs()); +} + +template +QualType TreeTransform::RebuildTypeOfType(QualType Underlying) { + return SemaRef.Context.getTypeOfType(Underlying); +} + +template +QualType TreeTransform::RebuildDecltypeType(Sema::ExprArg E) { + return SemaRef.BuildDecltypeType(E.takeAs()); +} + +template +QualType TreeTransform::RebuildTemplateSpecializationType( + TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs) { + // FIXME: Missing source locations for the template name, <, >. + return SemaRef.CheckTemplateIdType(Template, getDerived().getBaseLocation(), + SourceLocation(), Args, NumArgs, + SourceLocation()); +} + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H