//===------- SemaTemplateInstantiate.cpp - C++ Template Instantiation ------===/ // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. //===----------------------------------------------------------------------===/ // // This file implements C++ template instantiation. // //===----------------------------------------------------------------------===/ #include "Sema.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/DeclTemplate.h" #include "clang/Parse/DeclSpec.h" #include "clang/Basic/LangOptions.h" #include "llvm/Support/Compiler.h" using namespace clang; //===----------------------------------------------------------------------===/ // Template Instantiation Support //===----------------------------------------------------------------------===/ /// \brief Retrieve the template argument list that should be used to /// instantiate the given declaration. const TemplateArgumentList & Sema::getTemplateInstantiationArgs(NamedDecl *D) { // Template arguments for a class template specialization. if (ClassTemplateSpecializationDecl *Spec = dyn_cast(D)) return Spec->getTemplateArgs(); // Template arguments for a function template specialization. if (FunctionDecl *Function = dyn_cast(D)) if (const TemplateArgumentList *TemplateArgs = Function->getTemplateSpecializationArgs()) return *TemplateArgs; // Template arguments for a member of a class template specialization. DeclContext *EnclosingTemplateCtx = D->getDeclContext(); while (!isa(EnclosingTemplateCtx)) { assert(!EnclosingTemplateCtx->isFileContext() && "Tried to get the instantiation arguments of a non-template"); EnclosingTemplateCtx = EnclosingTemplateCtx->getParent(); } ClassTemplateSpecializationDecl *EnclosingTemplate = cast(EnclosingTemplateCtx); return EnclosingTemplate->getTemplateArgs(); } Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange) : SemaRef(SemaRef) { Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast(Entity); Inst.TemplateArgs = 0; Inst.NumTemplateArgs = 0; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); Invalid = false; } } Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) : SemaRef(SemaRef) { Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast(Template); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); Invalid = false; } } Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, SourceRange InstantiationRange) : SemaRef(SemaRef) { Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind = Kind; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast(FunctionTemplate); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); Invalid = false; } } Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange) : SemaRef(SemaRef) { Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); if (!Invalid) { ActiveTemplateInstantiation Inst; Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; Inst.PointOfInstantiation = PointOfInstantiation; Inst.Entity = reinterpret_cast(PartialSpec); Inst.TemplateArgs = TemplateArgs; Inst.NumTemplateArgs = NumTemplateArgs; Inst.InstantiationRange = InstantiationRange; SemaRef.ActiveTemplateInstantiations.push_back(Inst); Invalid = false; } } void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } } bool Sema::InstantiatingTemplate::CheckInstantiationDepth( SourceLocation PointOfInstantiation, SourceRange InstantiationRange) { if (SemaRef.ActiveTemplateInstantiations.size() <= SemaRef.getLangOptions().InstantiationDepth) return false; SemaRef.Diag(PointOfInstantiation, diag::err_template_recursion_depth_exceeded) << SemaRef.getLangOptions().InstantiationDepth << InstantiationRange; SemaRef.Diag(PointOfInstantiation, diag::note_template_recursion_depth) << SemaRef.getLangOptions().InstantiationDepth; return true; } /// \brief Prints the current instantiation stack through a series of /// notes. void Sema::PrintInstantiationStack() { // FIXME: In all of these cases, we need to show the template arguments for (llvm::SmallVector::reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; ++Active) { switch (Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: { Decl *D = reinterpret_cast(Active->Entity); if (CXXRecordDecl *Record = dyn_cast(D)) { unsigned DiagID = diag::note_template_member_class_here; if (isa(Record)) DiagID = diag::note_template_class_instantiation_here; Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), DiagID) << Context.getTypeDeclType(Record) << Active->InstantiationRange; } else { FunctionDecl *Function = cast(D); unsigned DiagID; if (Function->getPrimaryTemplate()) DiagID = diag::note_function_template_spec_here; else DiagID = diag::note_template_member_function_here; Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), DiagID) << Function << Active->InstantiationRange; } break; } case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: { TemplateDecl *Template = cast((Decl *)Active->Entity); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( Active->TemplateArgs, Active->NumTemplateArgs, Context.PrintingPolicy); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_default_arg_instantiation_here) << (Template->getNameAsString() + TemplateArgsStr) << Active->InstantiationRange; break; } case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: { FunctionTemplateDecl *FnTmpl = cast((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_explicit_template_arg_substitution_here) << FnTmpl << Active->InstantiationRange; break; } case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast( (Decl *)Active->Entity)) { Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_partial_spec_deduct_instantiation_here) << Context.getTypeDeclType(PartialSpec) << Active->InstantiationRange; } else { FunctionTemplateDecl *FnTmpl = cast((Decl *)Active->Entity); Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), diag::note_function_template_deduction_instantiation_here) << FnTmpl << Active->InstantiationRange; } break; } } } bool Sema::isSFINAEContext() const { using llvm::SmallVector; for (SmallVector::const_reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; ++Active) { switch(Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: // This is a template instantiation, so there is no SFINAE. return false; case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: // A default template argument instantiation may or may not be a // SFINAE context; look further up the stack. break; case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: // We're either substitution explicitly-specified template arguments // or deduced template arguments, so SFINAE applies. return true; } } return false; } //===----------------------------------------------------------------------===/ // Template Instantiation for Types //===----------------------------------------------------------------------===/ namespace { class VISIBILITY_HIDDEN TemplateTypeInstantiator { Sema &SemaRef; 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); } 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); } 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 }; 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(), Loc, Entity); } 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(), Loc, 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(), Loc, 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(); } 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); } 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()); } 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); } 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); } QualType TemplateTypeInstantiator:: InstantiateTemplateTypeParmType(const TemplateTypeParmType *T) const { if (T->getDepth() == 0) { // Replace the template type parameter with its corresponding // template argument. // 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 // arguments left unspecified. if (T->getIndex() >= TemplateArgs.size() || TemplateArgs[T->getIndex()].isNull()) return QualType(T, 0); // Would be nice to keep the original type here assert(TemplateArgs[T->getIndex()].getKind() == TemplateArgument::Type && "Template argument kind mismatch"); return TemplateArgs[T->getIndex()].getAsType(); } // The template type parameter comes from an inner template (e.g., // 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(); } QualType TemplateTypeInstantiator:: InstantiateObjCQualifiedInterfaceType( const ObjCQualifiedInterfaceType *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. if (!Result.isNull() && T.getCVRQualifiers() && !Result->isFunctionType() && !Result->isReferenceType()) Result = Result.getWithAdditionalQualifiers(T.getCVRQualifiers()); return Result; } /// \brief Instantiate the type T with a given set of template arguments. /// /// This routine substitutes the given template arguments into the /// type T and produces the instantiated type. /// /// \param T the type into which the template arguments will be /// substituted. If this type is not dependent, it will be returned /// immediately. /// /// \param TemplateArgs the template arguments that will be /// substituted for the top-level template parameters within T. /// /// \param Loc the location in the source code where this substitution /// is being performed. It will typically be the location of the /// declarator (if we're instantiating the type of some declaration) /// or the location of the type in the source code (if, e.g., we're /// instantiating the type of a cast expression). /// /// \param Entity the name of the entity associated with a declaration /// being instantiated (if any). May be empty to indicate that there /// is no such entity (if, e.g., this is a type that occurs as part of /// a cast expression) or that the entity has no name (e.g., an /// unnamed function parameter). /// /// \returns If the instantiation succeeds, the instantiated /// type. Otherwise, produces diagnostics and returns a NULL type. QualType Sema::InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); // If T is not a dependent type, there is nothing to do. if (!T->isDependentType()) return T; TemplateTypeInstantiator Instantiator(*this, TemplateArgs, Loc, Entity); return Instantiator(T); } /// \brief Instantiate the base class specifiers of the given class /// template specialization. /// /// Produces a diagnostic and returns true on error, returns false and /// attaches the instantiated base classes to the class template /// specialization if successful. bool Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const TemplateArgumentList &TemplateArgs) { bool Invalid = false; llvm::SmallVector InstantiatedBases; for (ClassTemplateSpecializationDecl::base_class_iterator Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end(); Base != BaseEnd; ++Base) { if (!Base->getType()->isDependentType()) { // FIXME: Allocate via ASTContext InstantiatedBases.push_back(new CXXBaseSpecifier(*Base)); continue; } QualType BaseType = InstantiateType(Base->getType(), TemplateArgs, Base->getSourceRange().getBegin(), DeclarationName()); if (BaseType.isNull()) { Invalid = true; continue; } if (CXXBaseSpecifier *InstantiatedBase = CheckBaseSpecifier(Instantiation, Base->getSourceRange(), Base->isVirtual(), Base->getAccessSpecifierAsWritten(), BaseType, /*FIXME: Not totally accurate */ Base->getSourceRange().getBegin())) InstantiatedBases.push_back(InstantiatedBase); else Invalid = true; } if (!Invalid && AttachBaseSpecifiers(Instantiation, InstantiatedBases.data(), InstantiatedBases.size())) Invalid = true; return Invalid; } /// \brief Instantiate the definition of a class from a given pattern. /// /// \param PointOfInstantiation The point of instantiation within the /// source code. /// /// \param Instantiation is the declaration whose definition is being /// instantiated. This will be either a class template specialization /// or a member class of a class template specialization. /// /// \param Pattern is the pattern from which the instantiation /// occurs. This will be either the declaration of a class template or /// the declaration of a member class of a class template. /// /// \param TemplateArgs The template arguments to be substituted into /// the pattern. /// /// \returns true if an error occurred, false otherwise. bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const TemplateArgumentList &TemplateArgs, bool ExplicitInstantiation) { bool Invalid = false; CXXRecordDecl *PatternDef = cast_or_null(Pattern->getDefinition(Context)); if (!PatternDef) { if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_member_of_template_here); } else { Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) << ExplicitInstantiation << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_template_decl_here); } return true; } Pattern = PatternDef; InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst) return true; // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. DeclContext *PreviousContext = CurContext; CurContext = Instantiation; // Start the definition of this instantiation. Instantiation->startDefinition(); // Instantiate the base class specifiers. if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) Invalid = true; llvm::SmallVector Fields; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { Decl *NewMember = InstantiateDecl(*Member, Instantiation, TemplateArgs); if (NewMember) { if (NewMember->isInvalidDecl()) Invalid = true; else if (FieldDecl *Field = dyn_cast(NewMember)) Fields.push_back(DeclPtrTy::make(Field)); } else { // FIXME: Eventually, a NULL return will mean that one of the // instantiations was a semantic disaster, and we'll want to set Invalid = // true. For now, we expect to skip some members that we can't yet handle. } } // Finish checking fields. ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); // Add any implicitly-declared members that we might need. AddImplicitlyDeclaredMembersToClass(Instantiation); // Exit the scope of this instantiation. CurContext = PreviousContext; if (!Invalid) Consumer.HandleTagDeclDefinition(Instantiation); // If this is an explicit instantiation, instantiate our members, too. if (!Invalid && ExplicitInstantiation) { Inst.Clear(); InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs); } return Invalid; } bool Sema::InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, bool ExplicitInstantiation) { // Perform the actual instantiation on the canonical declaration. ClassTemplateSpec = cast( Context.getCanonicalDecl(ClassTemplateSpec)); // We can only instantiate something that hasn't already been // instantiated or specialized. Fail without any diagnostics: our // caller will provide an error message. if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared) return true; ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); CXXRecordDecl *Pattern = Template->getTemplatedDecl(); const TemplateArgumentList *TemplateArgs = &ClassTemplateSpec->getTemplateArgs(); // C++ [temp.class.spec.match]p1: // When a class template is used in a context that requires an // instantiation of the class, it is necessary to determine // whether the instantiation is to be generated using the primary // template or one of the partial specializations. This is done by // matching the template arguments of the class template // specialization with the template argument lists of the partial // specializations. typedef std::pair MatchResult; llvm::SmallVector Matched; for (llvm::FoldingSet::iterator Partial = Template->getPartialSpecializations().begin(), PartialEnd = Template->getPartialSpecializations().end(); Partial != PartialEnd; ++Partial) { TemplateDeductionInfo Info(Context); if (TemplateDeductionResult Result = DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { // FIXME: Store the failed-deduction information for use in // diagnostics, later. (void)Result; } else { Matched.push_back(std::make_pair(&*Partial, Info.take())); } } if (Matched.size() == 1) { // -- If exactly one matching specialization is found, the // instantiation is generated from that specialization. Pattern = Matched[0].first; TemplateArgs = Matched[0].second; } else if (Matched.size() > 1) { // -- If more than one matching specialization is found, the // partial order rules (14.5.4.2) are used to determine // whether one of the specializations is more specialized // than the others. If none of the specializations is more // specialized than all of the other matching // specializations, then the use of the class template is // ambiguous and the program is ill-formed. // FIXME: Implement partial ordering of class template partial // specializations. Diag(ClassTemplateSpec->getLocation(), diag::unsup_template_partial_spec_ordering); } else { // -- If no matches are found, the instantiation is generated // from the primary template. // Since we initialized the pattern and template arguments from // the primary template, there is nothing more we need to do here. } // Note that this is an instantiation. ClassTemplateSpec->setSpecializationKind( ExplicitInstantiation? TSK_ExplicitInstantiation : TSK_ImplicitInstantiation); bool Result = InstantiateClass(ClassTemplateSpec->getLocation(), ClassTemplateSpec, Pattern, *TemplateArgs, ExplicitInstantiation); for (unsigned I = 0, N = Matched.size(); I != N; ++I) { // FIXME: Implement TemplateArgumentList::Destroy! // if (Matched[I].first != Pattern) // Matched[I].second->Destroy(Context); } return Result; } /// \brief Instantiate the definitions of all of the member of the /// given class, which is an instantiation of a class template or a /// member class of a template. void Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, const TemplateArgumentList &TemplateArgs) { for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { if (FunctionDecl *Function = dyn_cast(*D)) { if (!Function->getBody()) InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast(*D)) { const VarDecl *Def = 0; if (!Var->getDefinition(Def)) InstantiateVariableDefinition(Var); } else if (CXXRecordDecl *Record = dyn_cast(*D)) { if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) { assert(Record->getInstantiatedFromMemberClass() && "Missing instantiated-from-template information"); InstantiateClass(PointOfInstantiation, Record, Record->getInstantiatedFromMemberClass(), TemplateArgs, true); } } } } /// \brief Instantiate the definitions of all of the members of the /// given class template specialization, which was named as part of an /// explicit instantiation. void Sema::InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec) { // C++0x [temp.explicit]p7: // An explicit instantiation that names a class template // specialization is an explicit instantion of the same kind // (declaration or definition) of each of its members (not // including members inherited from base classes) that has not // been previously explicitly specialized in the translation unit // containing the explicit instantiation, except as described // below. InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec, ClassTemplateSpec->getTemplateArgs()); } /// \brief Instantiate a nested-name-specifier. NestedNameSpecifier * Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range, const TemplateArgumentList &TemplateArgs) { // Instantiate the prefix of this nested name specifier. NestedNameSpecifier *Prefix = NNS->getPrefix(); if (Prefix) { Prefix = InstantiateNestedNameSpecifier(Prefix, Range, TemplateArgs); if (!Prefix) return 0; } switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: { assert(Prefix && "Can't have an identifier nested-name-specifier with no prefix"); CXXScopeSpec SS; // FIXME: The source location information is all wrong. SS.setRange(Range); SS.setScopeRep(Prefix); return static_cast( ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(), Range.getEnd(), *NNS->getAsIdentifier())); break; } case NestedNameSpecifier::Namespace: case NestedNameSpecifier::Global: return NNS; case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { QualType T = QualType(NNS->getAsType(), 0); if (!T->isDependentType()) return NNS; T = InstantiateType(T, TemplateArgs, Range.getBegin(), DeclarationName()); if (T.isNull()) return 0; if (T->isDependentType() || T->isRecordType() || (getLangOptions().CPlusPlus0x && T->isEnumeralType())) { assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here"); return NestedNameSpecifier::Create(Context, Prefix, NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, T.getTypePtr()); } Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T; return 0; } } // Required to silence a GCC warning return 0; } TemplateName Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc, const TemplateArgumentList &TemplateArgs) { if (TemplateTemplateParmDecl *TTP = dyn_cast_or_null( Name.getAsTemplateDecl())) { assert(TTP->getDepth() == 0 && "Cannot reduce depth of a template template parameter"); assert(TemplateArgs[TTP->getPosition()].getAsDecl() && "Wrong kind of template template argument"); ClassTemplateDecl *ClassTemplate = dyn_cast( TemplateArgs[TTP->getPosition()].getAsDecl()); assert(ClassTemplate && "Expected a class template"); if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { NestedNameSpecifier *NNS = InstantiateNestedNameSpecifier(QTN->getQualifier(), /*FIXME=*/SourceRange(Loc), TemplateArgs); if (NNS) return Context.getQualifiedTemplateName(NNS, QTN->hasTemplateKeyword(), ClassTemplate); } return TemplateName(ClassTemplate); } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { NestedNameSpecifier *NNS = InstantiateNestedNameSpecifier(DTN->getQualifier(), /*FIXME=*/SourceRange(Loc), TemplateArgs); if (!NNS) // FIXME: Not the best recovery strategy. return Name; if (NNS->isDependent()) return Context.getDependentTemplateName(NNS, DTN->getName()); // Somewhat redundant with ActOnDependentTemplateName. CXXScopeSpec SS; SS.setRange(SourceRange(Loc)); SS.setScopeRep(NNS); TemplateTy Template; TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS); if (TNK == TNK_Non_template) { Diag(Loc, diag::err_template_kw_refers_to_non_template) << DTN->getName(); return Name; } else if (TNK == TNK_Function_template) { Diag(Loc, diag::err_template_kw_refers_to_non_template) << DTN->getName(); return Name; } return Template.getAsVal(); } // FIXME: Even if we're referring to a Decl that isn't a template template // parameter, we may need to instantiate the outer contexts of that // Decl. However, this won't be needed until we implement member templates. return Name; } TemplateArgument Sema::Instantiate(TemplateArgument Arg, const TemplateArgumentList &TemplateArgs) { switch (Arg.getKind()) { case TemplateArgument::Null: assert(false && "Should never have a NULL template argument"); break; case TemplateArgument::Type: { QualType T = InstantiateType(Arg.getAsType(), TemplateArgs, Arg.getLocation(), DeclarationName()); if (T.isNull()) return TemplateArgument(); return TemplateArgument(Arg.getLocation(), T); } case TemplateArgument::Declaration: // FIXME: Template instantiation for template template parameters. return Arg; case TemplateArgument::Integral: return Arg; case TemplateArgument::Expression: { // Template argument expressions are not potentially evaluated. EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs); if (E.isInvalid()) return TemplateArgument(); return TemplateArgument(E.takeAs()); } case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); break; } assert(false && "Unhandled template argument kind"); return TemplateArgument(); }