diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 58 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 67 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 58 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 6 |
5 files changed, 141 insertions, 49 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 644ff35c3e..8832447314 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -542,7 +542,6 @@ DeduceTemplateArguments(Sema &S, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF) { // Fast-path check to see if we have too many/too few arguments. - // FIXME: Variadic templates broken! if (NumParams != NumArgs && !(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) && !(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1]))) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index c4f91f9ff6..71ccb06212 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -617,6 +617,10 @@ namespace { NumExpansions); } + void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { + SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack); + } + /// \brief Transform the given declaration by instantiating a reference to /// this declaration. Decl *TransformDecl(SourceLocation Loc, Decl *D); @@ -1154,12 +1158,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = 0; - bool WasParameterPack = false; - bool IsParameterPack = false; TypeLoc OldTL = OldDI->getTypeLoc(); if (isa<PackExpansionTypeLoc>(OldTL)) { PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL); - WasParameterPack = true; // We have a function parameter pack. Substitute into the pattern of the // expansion. @@ -1173,7 +1174,6 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // our function parameter is still a function parameter pack. // Therefore, make its type a pack expansion type. NewDI = CheckPackExpansion(NewDI, ExpansionTL.getEllipsisLoc()); - IsParameterPack = true; } } else { NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), @@ -1211,8 +1211,13 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // FIXME: When OldParm is a parameter pack and NewParm is not a parameter // pack, we actually have a set of instantiated locations. Maintain this set! - if (!WasParameterPack || IsParameterPack) + if (OldParm->isParameterPack() && !NewParm->isParameterPack()) { + // Add the new parameter to + CurrentInstantiationScope->InstantiatedLocalPackArg(OldParm, NewParm); + } else { + // Introduce an Old -> New mapping CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + } // FIXME: OldParm may come from a FunctionProtoType, in which case CurContext // can be anything, is this right ? @@ -1227,7 +1232,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, bool Sema::SubstParmTypes(SourceLocation Loc, ParmVarDecl **Params, unsigned NumParams, const MultiLevelTemplateArgumentList &TemplateArgs, - llvm::SmallVectorImpl<QualType> &ParamTypes) { + llvm::SmallVectorImpl<QualType> &ParamTypes, + llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -1235,7 +1241,7 @@ bool Sema::SubstParmTypes(SourceLocation Loc, TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, DeclarationName()); return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, 0, - ParamTypes, 0); + ParamTypes, OutParams); } /// \brief Perform substitution on the base class specifiers of the @@ -1899,15 +1905,27 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, } Decl *LocalInstantiationScope::getInstantiationOf(const Decl *D) { + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found= findInstantiationOf(D); + if (!Found) + return 0; + + if (Found->is<Decl *>()) + return Found->get<Decl *>(); + + return (*Found->get<DeclArgumentPack *>())[ + SemaRef.ArgumentPackSubstitutionIndex]; +} + +llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> * +LocalInstantiationScope::findInstantiationOf(const Decl *D) { for (LocalInstantiationScope *Current = this; Current; Current = Current->Outer) { // Check if we found something within this scope. const Decl *CheckD = D; do { - llvm::DenseMap<const Decl *, Decl *>::iterator Found - = Current->LocalDecls.find(CheckD); + LocalDeclsMap::iterator Found = Current->LocalDecls.find(CheckD); if (Found != Current->LocalDecls.end()) - return Found->second; + return &Found->second; // If this is a tag declaration, it's possible that we need to look for // a previous declaration. @@ -1928,7 +1946,23 @@ Decl *LocalInstantiationScope::getInstantiationOf(const Decl *D) { } void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { - Decl *&Stored = LocalDecls[D]; - assert((!Stored || Stored == Inst)&& "Already instantiated this local"); + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; + assert((Stored.isNull() || + (Stored.get<Decl *>() == Inst)) && "Already instantiated this local"); Stored = Inst; } + +void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, + Decl *Inst) { + DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>(); + Pack->push_back(Inst); +} + +void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; + assert(Stored.isNull() && "Already instantiated this local"); + DeclArgumentPack *Pack = new DeclArgumentPack; + Stored = Pack; + ArgumentPacks.push_back(Pack); +} + diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 92521ae16e..2ef688b0eb 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1271,14 +1271,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, // synthesized in the method declaration. if (!isa<FunctionProtoType>(T.IgnoreParens())) { assert(!Params.size() && "Instantiating type could not yield parameters"); - for (unsigned I = 0, N = D->getNumParams(); I != N; ++I) { - ParmVarDecl *P = SemaRef.SubstParmVarDecl(D->getParamDecl(I), - TemplateArgs); - if (!P) - return 0; - - Params.push_back(P); - } + llvm::SmallVector<QualType, 4> ParamTypes; + if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), + D->getNumParams(), TemplateArgs, ParamTypes, + &Params)) + return 0; } NestedNameSpecifier *Qualifier = D->getQualifier(); @@ -1904,12 +1901,31 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens(); FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); assert(NewProtoLoc && "Missing prototype?"); - for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) { - // FIXME: Variadic templates will break this. - Params.push_back(NewProtoLoc->getArg(i)); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - OldProtoLoc->getArg(i), - NewProtoLoc->getArg(i)); + unsigned NewIdx = 0, NumNewParams = NewProtoLoc->getNumArgs(); + for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs(); + OldIdx != NumOldParams; ++OldIdx) { + ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx); + if (!OldParam->isParameterPack() || + (NewIdx < NumNewParams && + NewProtoLoc->getArg(NewIdx)->isParameterPack())) { + // Simple case: normal parameter, or a parameter pack that's + // instantiated to a (still-dependent) parameter pack. + ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++); + Params.push_back(NewParam); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam, + NewParam); + continue; + } + + // Parameter pack: make the instantiation an argument pack. + SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack( + OldParam); + while (NewIdx < NumNewParams) { + ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++); + Params.push_back(NewParam); + SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(OldParam, + NewParam); + } } } } else { @@ -2179,11 +2195,28 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Introduce the instantiated function parameters into the local // instantiation scope, and set the parameter names to those used // in the template. + unsigned FParamIdx = 0; for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) { const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I); - ParmVarDecl *FunctionParam = Function->getParamDecl(I); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocal(PatternParam, FunctionParam); + if (!PatternParam->isParameterPack()) { + // Simple case: not a parameter pack. + assert(FParamIdx < Function->getNumParams()); + ParmVarDecl *FunctionParam = Function->getParamDecl(I); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocal(PatternParam, FunctionParam); + ++FParamIdx; + continue; + } + + // Expand the parameter pack. + Scope.MakeInstantiatedLocalArgPack(PatternParam); + for (unsigned NumFParams = Function->getNumParams(); + FParamIdx < NumFParams; + ++FParamIdx) { + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + } } // Enter the scope of this instantiation. We don't use diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 3090d1532d..1928c59642 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -67,13 +67,8 @@ namespace { /// \brief Record occurrences of (FIXME: function and) non-type template /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) { - if (NTTP->isParameterPack()) - Unexpanded.push_back(std::make_pair(NTTP, E->getLocation())); - } - - // FIXME: Function parameter packs. + if (E->getDecl()->isParameterPack()) + Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation())); return true; } @@ -440,6 +435,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, unsigned Depth; unsigned Index; IdentifierInfo *Name; + bool IsFunctionParameterPack = false; if (const TemplateTypeParmType *TTP = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { @@ -455,26 +451,50 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, = dyn_cast<NonTypeTemplateParmDecl>(ND)) { Depth = NTTP->getDepth(); Index = NTTP->getIndex(); - } else { - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + } else if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { Depth = TTP->getDepth(); Index = TTP->getIndex(); + } else { + assert(cast<ParmVarDecl>(ND)->isParameterPack()); + IsFunctionParameterPack = true; } - // FIXME: Variadic templates function parameter packs? Name = ND->getIdentifier(); } - // If we don't have a template argument at this depth/index, then we - // cannot expand the pack expansion. Make a note of this, but we still - // want to check any parameter packs we *do* have arguments for. - if (Depth >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Depth, Index)) { - ShouldExpand = false; - continue; + // Determine the size of this argument pack. + unsigned NewPackSize; + if (IsFunctionParameterPack) { + // Figure out whether we're instantiating to an argument pack or not. + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation + = CurrentInstantiationScope->findInstantiationOf( + Unexpanded[I].first.get<NamedDecl *>()); + if (Instantiation && + Instantiation->is<DeclArgumentPack *>()) { + // We could expand this function parameter pack. + NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); + } else { + // We can't expand this function parameter pack, so we can't expand + // the pack expansion. + ShouldExpand = false; + continue; + } + } else { + // If we don't have a template argument at this depth/index, then we + // cannot expand the pack expansion. Make a note of this, but we still + // want to check any parameter packs we *do* have arguments for. + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) { + ShouldExpand = false; + continue; + } + + // Determine the size of the argument pack. + NewPackSize = TemplateArgs(Depth, Index).pack_size(); } - // Determine the size of the argument pack. - unsigned NewPackSize = TemplateArgs(Depth, Index).pack_size(); if (!HaveFirstPack) { // The is the first pack we've seen for which we have an argument. // Record it. diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 60ec950c12..0624aaa7ee 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -222,6 +222,10 @@ public: return false; } + /// \brief Note to the derived class when a function parameter pack is + /// being expanded. + void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { } + /// \brief Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a @@ -3423,6 +3427,7 @@ bool TreeTransform<Derived>:: if (ShouldExpand) { // Expand the function parameter pack into multiple, separate // parameters. + getDerived().ExpandingFunctionParameterPack(OldParm); for (unsigned I = 0; I != NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); ParmVarDecl *NewParm @@ -6875,6 +6880,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { llvm::SmallVector<QualType, 4> ParamTypes; // Parameter substitution. + // FIXME: Variadic templates const BlockDecl *BD = E->getBlockDecl(); for (BlockDecl::param_const_iterator P = BD->param_begin(), EN = BD->param_end(); P != EN; ++P) { |