diff options
| author | Douglas Gregor <dgregor@apple.com> | 2011-01-05 23:12:31 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2011-01-05 23:12:31 +0000 |
| commit | 5499af4ef9917edfbd146d023859965b42d2bc88 (patch) | |
| tree | e10b7d0c3802a36c1d85ad20436484a4be13dc3b /clang/lib/Sema | |
| parent | 260acf32ee670be89793116d59a5f2c65fe268b3 (diff) | |
| download | bcm5719-llvm-5499af4ef9917edfbd146d023859965b42d2bc88.tar.gz bcm5719-llvm-5499af4ef9917edfbd146d023859965b42d2bc88.zip | |
Initial implementation of function parameter packs. This implementation allows:
1) Declaration of function parameter packs
2) Instantiation of function parameter packs within function types.
3) Template argument deduction of function parameter packs when
matching two function types.
We're missing all of the important template-instantiation logic for
function template definitions, along with template argument deduction
from the argument list of a function call, so don't even think of
trying to use these for real yet.
llvm-svn: 122926
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 262 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 66 | ||||
| -rw-r--r-- | clang/lib/Sema/TreeTransform.h | 126 |
4 files changed, 391 insertions, 69 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1c03f7d7f77..28ae8d23c7b 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4986,12 +4986,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { << D.getCXXScopeSpec().getRange(); D.getCXXScopeSpec().clear(); } - - // FIXME: Variadic templates. - if (D.hasEllipsis()) { - Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_unsupported); - D.setInvalidType(); - } } // Ensure we have a valid name diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 0df2899855c..e762d341176 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -87,6 +87,15 @@ DeduceTemplateArguments(Sema &S, static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, + QualType Param, + QualType Arg, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned TDF); + +static Sema::TemplateDeductionResult +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, @@ -469,6 +478,209 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { } } +/// \brief Retrieve the depth and index of an unexpanded parameter pack. +static std::pair<unsigned, unsigned> +getDepthAndIndex(UnexpandedParameterPack UPP) { + if (const TemplateTypeParmType *TTP + = UPP.first.dyn_cast<const TemplateTypeParmType *>()) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + NamedDecl *ND = UPP.first.get<NamedDecl *>(); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) + return std::make_pair(TTP->getDepth(), TTP->getIndex()); + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) + return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + return std::make_pair(TTP->getDepth(), TTP->getIndex()); +} + +/// \brief Helper function to build a TemplateParameter when we don't +/// know its type statically. +static TemplateParameter makeTemplateParameter(Decl *D) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D)) + return TemplateParameter(TTP); + else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) + return TemplateParameter(NTTP); + + return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); +} + +/// \brief Deduce the template arguments by comparing the list of parameter +/// types to the list of argument types, as in the parameter-type-lists of +/// function types (C++ [temp.deduct.type]p10). +/// +/// \param S The semantic analysis object within which we are deducing +/// +/// \param TemplateParams The template parameters that we are deducing +/// +/// \param Params The list of parameter types +/// +/// \param NumParams The number of types in \c Params +/// +/// \param Args The list of argument types +/// +/// \param NumArgs The number of types in \c Args +/// +/// \param Info information about the template argument deduction itself +/// +/// \param Deduced the deduced template arguments +/// +/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe +/// how template argument deduction is performed. +/// +/// \returns the result of template argument deduction so far. Note that a +/// "success" result means that template argument deduction has not yet failed, +/// but it may still fail, later, for other reasons. +static Sema::TemplateDeductionResult +DeduceTemplateArguments(Sema &S, + TemplateParameterList *TemplateParams, + const QualType *Params, unsigned NumParams, + const QualType *Args, unsigned NumArgs, + TemplateDeductionInfo &Info, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned TDF) { + // FIXME: Fast-path check with NumParams != NumArgs and there are no + // pack expansions around. + + // C++0x [temp.deduct.type]p10: + // Similarly, if P has a form that contains (T), then each parameter type + // Pi of the respective parameter-type- list of P is compared with the + // corresponding parameter type Ai of the corresponding parameter-type-list + // of A. [...] + unsigned ArgIdx = 0, ParamIdx = 0; + for (; ParamIdx != NumParams; ++ParamIdx) { + // Check argument types. + const PackExpansionType *Expansion + = dyn_cast<PackExpansionType>(Params[ParamIdx]); + if (!Expansion) { + // Simple case: compare the parameter and argument types at this point. + + // Make sure we have an argument. + if (ArgIdx >= NumArgs) + return Sema::TDK_TooFewArguments; + + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, + Params[ParamIdx], + Args[ArgIdx], + Info, Deduced, TDF)) + return Result; + + ++ArgIdx; + continue; + } + + // C++0x [temp.deduct.type]p10: + // If the parameter-declaration corresponding to Pi is a function + // parameter pack, then the type of its declarator- id is compared with + // each remaining parameter type in the parameter-type-list of A. Each + // comparison deduces template arguments for subsequent positions in the + // template parameter packs expanded by the function parameter pack. + + // Compute the set of template parameter indices that correspond to + // parameter packs expanded by the pack expansion. + llvm::SmallVector<unsigned, 2> PackIndices; + QualType Pattern = Expansion->getPattern(); + { + llvm::BitVector SawIndices(TemplateParams->size()); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + llvm::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == 0 && !SawIndices[Index]) { + SawIndices[Index] = true; + PackIndices.push_back(Index); + } + } + } + assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?"); + + // Save the deduced template arguments for each parameter pack expanded + // by this pack expansion, then clear out the deduction. + llvm::SmallVector<DeducedTemplateArgument, 2> + SavedPacks(PackIndices.size()); + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + SavedPacks[I] = Deduced[PackIndices[I]]; + Deduced[PackIndices[I]] = DeducedTemplateArgument(); + } + + // Keep track of the deduced template arguments for each parameter pack + // expanded by this pack expansion (the outer index) and for each + // template argument (the inner SmallVectors). + llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2> + NewlyDeducedPacks(PackIndices.size()); + bool HasAnyArguments = false; + for (; ArgIdx < NumArgs; ++ArgIdx) { + HasAnyArguments = true; + + // Deduce template arguments from the pattern. + if (Sema::TemplateDeductionResult Result + = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], + Info, Deduced)) + return Result; + + // Capture the deduced template arguments for each parameter pack expanded + // by this pack expansion, add them to the list of arguments we've deduced + // for that pack, then clear out the deduced argument. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + DeducedTemplateArgument &DeducedArg = Deduced[PackIndices[I]]; + if (!DeducedArg.isNull()) { + NewlyDeducedPacks[I].push_back(DeducedArg); + DeducedArg = DeducedTemplateArgument(); + } + } + } + + // Build argument packs for each of the parameter packs expanded by this + // pack expansion. + for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) { + if (HasAnyArguments && NewlyDeducedPacks[I].empty()) { + // We were not able to deduce anything for this parameter pack, + // so just restore the saved argument pack. + Deduced[PackIndices[I]] = SavedPacks[I]; + continue; + } + + DeducedTemplateArgument NewPack; + + if (NewlyDeducedPacks[I].empty()) { + // If we deduced an empty argument pack, create it now. + NewPack = DeducedTemplateArgument(TemplateArgument(0, 0)); + } else { + TemplateArgument *ArgumentPack + = new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()]; + std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(), + ArgumentPack); + NewPack + = DeducedTemplateArgument(TemplateArgument(ArgumentPack, + NewlyDeducedPacks[I].size()), + NewlyDeducedPacks[I][0].wasDeducedFromArrayBound()); + } + + DeducedTemplateArgument Result + = checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack); + if (Result.isNull()) { + Info.Param + = makeTemplateParameter(TemplateParams->getParam(PackIndices[I])); + Info.FirstArg = SavedPacks[I]; + Info.SecondArg = NewPack; + return Sema::TDK_Inconsistent; + } + + Deduced[PackIndices[I]] = Result; + } + } + + // Make sure we don't have any extra arguments. + if (ArgIdx < NumArgs) + return Sema::TDK_TooManyArguments; + + return Sema::TDK_Success; +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -740,9 +952,6 @@ DeduceTemplateArguments(Sema &S, FunctionProtoArg->getTypeQuals()) return Sema::TDK_NonDeducedMismatch; - if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs()) - return Sema::TDK_NonDeducedMismatch; - if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) return Sema::TDK_NonDeducedMismatch; @@ -754,18 +963,12 @@ DeduceTemplateArguments(Sema &S, Info, Deduced, 0)) return Result; - for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) { - // Check argument types. - // FIXME: Variadic templates. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - FunctionProtoParam->getArgType(I), - FunctionProtoArg->getArgType(I), - Info, Deduced, 0)) - return Result; - } - - return Sema::TDK_Success; + return DeduceTemplateArguments(S, TemplateParams, + FunctionProtoParam->arg_type_begin(), + FunctionProtoParam->getNumArgs(), + FunctionProtoArg->arg_type_begin(), + FunctionProtoArg->getNumArgs(), + Info, Deduced, 0); } case Type::InjectedClassName: { @@ -1045,35 +1248,6 @@ static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args, return ArgIdx < NumArgs; } -/// \brief Retrieve the depth and index of an unexpanded parameter pack. -static std::pair<unsigned, unsigned> -getDepthAndIndex(UnexpandedParameterPack UPP) { - if (const TemplateTypeParmType *TTP - = UPP.first.dyn_cast<const TemplateTypeParmType *>()) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - NamedDecl *ND = UPP.first.get<NamedDecl *>(); - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) - return std::make_pair(TTP->getDepth(), TTP->getIndex()); - - if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND)) - return std::make_pair(NTTP->getDepth(), NTTP->getIndex()); - - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); - return std::make_pair(TTP->getDepth(), TTP->getIndex()); -} - -/// \brief Helper function to build a TemplateParameter when we don't -/// know its type statically. -static TemplateParameter makeTemplateParameter(Decl *D) { - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D)) - return TemplateParameter(TTP); - else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) - return TemplateParameter(NTTP); - - return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); -} - /// \brief Determine whether the given set of template arguments has a pack /// expansion that is not the last template argument. static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 46d8c1d3d46..7deb7cad3bf 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1052,6 +1052,36 @@ TypeSourceInfo *Sema::SubstType(TypeSourceInfo *T, return Instantiator.TransformType(T); } +TypeSourceInfo *Sema::SubstType(TypeLoc TL, + const MultiLevelTemplateArgumentList &Args, + SourceLocation Loc, + DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + if (TL.getType().isNull()) + return 0; + + if (!TL.getType()->isDependentType() && + !TL.getType()->isVariablyModifiedType()) { + // FIXME: Make a copy of the TypeLoc data here, so that we can + // return a new TypeSourceInfo. Inefficient! + TypeLocBuilder TLB; + TLB.pushFullCopy(TL); + return TLB.getTypeSourceInfo(Context, TL.getType()); + } + + TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + TypeLocBuilder TLB; + TLB.reserve(TL.getFullDataSize()); + QualType Result = Instantiator.TransformType(TLB, TL); + if (Result.isNull()) + return 0; + + return TLB.getTypeSourceInfo(Context, Result); +} + /// Deprecated form of the above. QualType Sema::SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -1122,8 +1152,34 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), - OldParm->getDeclName()); + 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. + NewDI = SubstType(ExpansionTL.getPatternLoc(), TemplateArgs, + OldParm->getLocation(), OldParm->getDeclName()); + if (!NewDI) + return 0; + + if (NewDI->getType()->containsUnexpandedParameterPack()) { + // We still have unexpanded parameter packs, which means that + // 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(), + OldParm->getDeclName()); + } + if (!NewDI) return 0; @@ -1153,7 +1209,11 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); - CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + // 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) + CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + // FIXME: OldParm may come from a FunctionProtoType, in which case CurContext // can be anything, is this right ? NewParm->setDeclContext(CurContext); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5eb0d55a39d..3bd81561e0d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3396,34 +3396,128 @@ bool TreeTransform<Derived>:: FunctionProtoType *T = TL.getTypePtr(); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - ParmVarDecl *OldParm = TL.getArg(i); - - QualType NewType; - ParmVarDecl *NewParm; - - if (OldParm) { - NewParm = getDerived().TransformFunctionTypeParam(OldParm); + if (ParmVarDecl *OldParm = TL.getArg(i)) { + if (OldParm->isParameterPack()) { + // We have a function parameter pack that may need to be expanded. + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + + // Find the parameter packs that could be expanded. + SourceLocation EllipsisLoc; + SourceRange PatternRange; + if (OldParm->getTypeSourceInfo()) { + TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc(); + PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL); + TypeLoc Pattern = ExpansionTL.getPatternLoc(); + EllipsisLoc = ExpansionTL.getEllipsisLoc(); + PatternRange = Pattern.getSourceRange(); + SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); + } else { + SemaRef.collectUnexpandedParameterPacks( + cast<PackExpansionType>(OldParm->getType())->getPattern(), + Unexpanded); + EllipsisLoc = OldParm->getLocation(); + } + + // Determine whether we should expand the parameter packs. + bool ShouldExpand = false; + unsigned NumExpansions = 0; + if (getDerived().TryExpandParameterPacks(EllipsisLoc, PatternRange, + Unexpanded.data(), + Unexpanded.size(), + ShouldExpand, NumExpansions)) { + return true; + } + + if (ShouldExpand) { + // Expand the function parameter pack into multiple, separate + // parameters. + for (unsigned I = 0; I != NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + ParmVarDecl *NewParm + = getDerived().TransformFunctionTypeParam(OldParm); + if (!NewParm) + return true; + + PTypes.push_back(NewParm->getType()); + PVars.push_back(NewParm); + } + + // We're done with the pack expansion. + continue; + } + + // We'll substitute the parameter now without expanding the pack + // expansion. + } + + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm); if (!NewParm) return true; - NewType = NewParm->getType(); + + PTypes.push_back(NewParm->getType()); + PVars.push_back(NewParm); + continue; + } // Deal with the possibility that we don't have a parameter // declaration for this parameter. - } else { - NewParm = 0; - - QualType OldType = T->getArgType(i); - NewType = getDerived().TransformType(OldType); - if (NewType.isNull()) + QualType OldType = T->getArgType(i); + bool IsPackExpansion = false; + if (const PackExpansionType *Expansion + = dyn_cast<PackExpansionType>(OldType)) { + // We have a function parameter pack that may need to be expanded. + QualType Pattern = Expansion->getPattern(); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + + // Determine whether we should expand the parameter packs. + bool ShouldExpand = false; + unsigned NumExpansions = 0; + if (getDerived().TryExpandParameterPacks(TL.getBeginLoc(), SourceRange(), + Unexpanded.data(), + Unexpanded.size(), + ShouldExpand, NumExpansions)) { return true; + } + + if (ShouldExpand) { + // Expand the function parameter pack into multiple, separate + // parameters. + for (unsigned I = 0; I != NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + QualType NewType = getDerived().TransformType(Pattern); + if (NewType.isNull()) + return true; + + PTypes.push_back(NewType); + PVars.push_back(0); + } + + // We're done with the pack expansion. + continue; + } + + // We'll substitute the parameter now without expanding the pack + // expansion. + OldType = Expansion->getPattern(); + IsPackExpansion = true; } + + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + QualType NewType = getDerived().TransformType(OldType); + if (NewType.isNull()) + return true; + if (IsPackExpansion) + NewType = getSema().Context.getPackExpansionType(NewType); + PTypes.push_back(NewType); - PVars.push_back(NewParm); + PVars.push_back(0); } return false; -} + } template<typename Derived> QualType |

