diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 146 |
5 files changed, 214 insertions, 32 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b2749bf6ce..a164e5c7b8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5967,8 +5967,6 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { cast<NonTypeTemplateParmDecl>(Params->getParam(0)); // The template parameter must be a char parameter pack. - // FIXME: This test will always fail because non-type parameter packs - // have not been implemented. if (PmDecl && PmDecl->isTemplateParameterPack() && Context.hasSameType(PmDecl->getType(), Context.CharTy)) Valid = true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f97c650d96..ad08a11f20 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2197,11 +2197,36 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, /// \brief Check that the given template argument corresponds to the given /// template parameter. +/// +/// \param Param The template parameter against which the argument will be +/// checked. +/// +/// \param Arg The template argument. +/// +/// \param Template The template in which the template argument resides. +/// +/// \param TemplateLoc The location of the template name for the template +/// whose argument list we're matching. +/// +/// \param RAngleLoc The location of the right angle bracket ('>') that closes +/// the template argument list. +/// +/// \param ArgumentPackIndex The index into the argument pack where this +/// argument will be placed. Only valid if the parameter is a parameter pack. +/// +/// \param Converted The checked, converted argument will be added to the +/// end of this small vector. +/// +/// \param CTAK Describes how we arrived at this particular template argument: +/// explicitly written, deduced, etc. +/// +/// \returns true on error, false otherwise. bool Sema::CheckTemplateArgument(NamedDecl *Param, const TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, + unsigned ArgumentPackIndex, llvm::SmallVectorImpl<TemplateArgument> &Converted, CheckTemplateArgumentKind CTAK) { // Check template type parameters. @@ -2214,6 +2239,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, // with the template arguments we've seen thus far. But if the // template has a dependent context then we cannot substitute yet. QualType NTTPType = NTTP->getType(); + if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) + NTTPType = NTTP->getExpansionType(ArgumentPackIndex); + if (NTTPType->isDependentType() && !isa<TemplateTemplateParmDecl>(Template) && !Template->getDeclContext()->isDependentContext()) { @@ -2447,9 +2475,28 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; if (ArgIdx < NumArgs) { + // If we have an expanded parameter pack, make sure we don't have too + // many arguments. + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + if (NTTP->isExpandedParameterPack() && + ArgumentPack.size() >= NTTP->getNumExpansionTypes()) { + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << true + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template; + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; + } + } + // Check the template argument we were given. if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, - TemplateLoc, RAngleLoc, Converted)) + TemplateLoc, RAngleLoc, + ArgumentPack.size(), Converted)) return true; if ((*Param)->isTemplateParameterPack()) { @@ -2544,7 +2591,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Check the default template argument. if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, - RAngleLoc, Converted)) + RAngleLoc, 0, Converted)) return true; // Move to the next template parameter and argument. diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 812c633c58..fc480391ea 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1705,6 +1705,7 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, QualType NTTPType, + unsigned ArgumentPackIndex, TemplateDeductionInfo &Info, bool InFunctionTemplate, llvm::SmallVectorImpl<TemplateArgument> &Output) { @@ -1721,8 +1722,8 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, DeducedTemplateArgument InnerArg(*PA); InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template, - NTTPType, Info, - InFunctionTemplate, Output)) + NTTPType, PackedArgsBuilder.size(), + Info, InFunctionTemplate, Output)) return true; // Move the converted template argument into our argument pack. @@ -1748,6 +1749,7 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, Template, Template->getLocation(), Template->getSourceRange().getEnd(), + ArgumentPackIndex, Output, InFunctionTemplate ? (Arg.wasDeducedFromArrayBound() @@ -1810,7 +1812,7 @@ FinishTemplateArgumentDeduction(Sema &S, } if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], - Partial, NTTPType, Info, false, + Partial, NTTPType, 0, Info, false, Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! @@ -2160,7 +2162,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, } if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I], - FunctionTemplate, NTTPType, Info, + FunctionTemplate, NTTPType, 0, Info, true, Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! @@ -2212,7 +2214,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, FunctionTemplate, FunctionTemplate->getLocation(), FunctionTemplate->getSourceRange().getEnd(), - Builder, + 0, Builder, CTAK_Deduced)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0ae8804481..45fde296e3 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1016,9 +1016,19 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, // Derive the type we want the substituted decl to have. This had // better be non-dependent, or these checks will have serious problems. - QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, - E->getLocation(), - DeclarationName()); + QualType TargetType; + if (NTTP->isExpandedParameterPack()) + TargetType = NTTP->getExpansionType( + getSema().ArgumentPackSubstitutionIndex); + else if (NTTP->isParameterPack() && + isa<PackExpansionType>(NTTP->getType())) { + TargetType = SemaRef.SubstType( + cast<PackExpansionType>(NTTP->getType())->getPattern(), + TemplateArgs, E->getLocation(), + NTTP->getDeclName()); + } else + TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, + E->getLocation(), NTTP->getDeclName()); assert(!TargetType.isNull() && "type substitution failed for param type"); assert(!TargetType->isDependentType() && "param type still dependent"); return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, @@ -1038,7 +1048,6 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( return getSema().Owned(E); } - // FIXME: Variadic templates select Nth from type? const TemplateArgument &ArgPack = E->getArgumentPack(); unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex; assert(Index < ArgPack.pack_size() && "Substitution index out-of-range"); @@ -1058,8 +1067,17 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( if (!VD) return ExprError(); - return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, - E->getType(), + QualType T; + NonTypeTemplateParmDecl *NTTP = E->getParameterPack(); + if (NTTP->isExpandedParameterPack()) + T = NTTP->getExpansionType(getSema().ArgumentPackSubstitutionIndex); + else if (const PackExpansionType *Expansion + = dyn_cast<PackExpansionType>(NTTP->getType())) + T = SemaRef.SubstType(Expansion->getPattern(), TemplateArgs, + E->getParameterPackLocation(), NTTP->getDeclName()); + else + T = E->getType(); + return SemaRef.BuildExpressionFromDeclTemplateArgument(Arg, T, E->getParameterPackLocation()); } @@ -1778,6 +1796,11 @@ Sema::InstantiateClassTemplateSpecialization( } } + // If we're dealing with a member template where the template parameters + // have been instantiated, this provides the original template parameters + // from which the member template's parameters were instantiated. + llvm::SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; + if (Matched.size() >= 1) { llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); if (Matched.size() == 1) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b4ccdd572d..fd7325cc01 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1455,28 +1455,140 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *D) { // Substitute into the type of the non-type template parameter. + TypeLoc TL = D->getTypeSourceInfo()->getTypeLoc(); + llvm::SmallVector<TypeSourceInfo *, 4> ExpandedParameterPackTypesAsWritten; + llvm::SmallVector<QualType, 4> ExpandedParameterPackTypes; + bool IsExpandedParameterPack = false; + TypeSourceInfo *DI; QualType T; - TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, D->getLocation(), - D->getDeclName()); - if (!DI) - return 0; - - T = DI->getType(); - - // Check that this type is acceptable for a non-type template parameter. bool Invalid = false; - T = SemaRef.CheckNonTypeTemplateParameterType(T, D->getLocation()); - if (T.isNull()) { - T = SemaRef.Context.IntTy; - Invalid = true; + + if (D->isExpandedParameterPack()) { + // The non-type template parameter pack is an already-expanded pack + // expansion of types. Substitute into each of the expanded types. + ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes()); + ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes()); + for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { + TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), + TemplateArgs, + D->getLocation(), + D->getDeclName()); + if (!NewDI) + return 0; + + ExpandedParameterPackTypesAsWritten.push_back(NewDI); + QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(), + D->getLocation()); + if (NewT.isNull()) + return 0; + ExpandedParameterPackTypes.push_back(NewT); + } + + IsExpandedParameterPack = true; + DI = D->getTypeSourceInfo(); + T = DI->getType(); + } else if (isa<PackExpansionTypeLoc>(TL)) { + // The non-type template parameter pack's type is a pack expansion of types. + // Determine whether we need to expand this parameter pack into separate + // types. + PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL); + TypeLoc Pattern = Expansion.getPatternLoc(); + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> OrigNumExpansions + = Expansion.getTypePtr()->getNumExpansions(); + llvm::Optional<unsigned> NumExpansions = OrigNumExpansions; + if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(), + Pattern.getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + TemplateArgs, + Expand, RetainExpansion, + NumExpansions)) + return 0; + + if (Expand) { + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + TypeSourceInfo *NewDI = SemaRef.SubstType(Pattern, TemplateArgs, + D->getLocation(), + D->getDeclName()); + if (!NewDI) + return 0; + + ExpandedParameterPackTypesAsWritten.push_back(NewDI); + QualType NewT = SemaRef.CheckNonTypeTemplateParameterType( + NewDI->getType(), + D->getLocation()); + if (NewT.isNull()) + return 0; + ExpandedParameterPackTypes.push_back(NewT); + } + + // Note that we have an expanded parameter pack. The "type" of this + // expanded parameter pack is the original expansion type, but callers + // will end up using the expanded parameter pack types for type-checking. + IsExpandedParameterPack = true; + DI = D->getTypeSourceInfo(); + T = DI->getType(); + } else { + // We cannot fully expand the pack expansion now, so substitute into the + // pattern and create a new pack expansion type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + TypeSourceInfo *NewPattern = SemaRef.SubstType(Pattern, TemplateArgs, + D->getLocation(), + D->getDeclName()); + if (!NewPattern) + return 0; + + DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(), + NumExpansions); + if (!DI) + return 0; + + T = DI->getType(); + } + } else { + // Simple case: substitution into a parameter that is not a parameter pack. + DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, + D->getLocation(), D->getDeclName()); + if (!DI) + return 0; + + // Check that this type is acceptable for a non-type template parameter. + bool Invalid = false; + T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), + D->getLocation()); + if (T.isNull()) { + T = SemaRef.Context.IntTy; + Invalid = true; + } } - // FIXME: Variadic templates. - NonTypeTemplateParmDecl *Param - = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + NonTypeTemplateParmDecl *Param; + if (IsExpandedParameterPack) + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->getIdentifier(), T, - D->isParameterPack(), DI); + D->getPosition(), + D->getIdentifier(), T, + DI, + ExpandedParameterPackTypes.data(), + ExpandedParameterPackTypes.size(), + ExpandedParameterPackTypesAsWritten.data()); + else + Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), + D->getIdentifier(), T, + D->isParameterPack(), DI); + if (Invalid) Param->setInvalidDecl(); |