Improve our handling of non-type template parameters in partial
specializations. We weren't dealing with any of the cases where the
type of the non-type template argument differs from the type of the
corresponding template parameter in the primary template. We would
think that the template parameter in the partial specialization was
not deducible (and warn about it, incorrectly), then fail to convert a
deduced parameter to the type of the template parameter in the partial
specialization (which may involve truncation, among other
things). Fixes PR8905.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122851 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 3c3f3d7..09bfcf5 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1314,6 +1314,114 @@
return false;
}
+/// \brief Allocate a TemplateArgumentLoc where all locations have
+/// been initialized to the given location.
+///
+/// \param S The semantic analysis object.
+///
+/// \param The template argument we are producing template argument
+/// location information for.
+///
+/// \param NTTPType For a declaration template argument, the type of
+/// the non-type template parameter that corresponds to this template
+/// argument.
+///
+/// \param Loc The source location to use for the resulting template
+/// argument.
+static TemplateArgumentLoc
+getTrivialTemplateArgumentLoc(Sema &S,
+ const TemplateArgument &Arg,
+ QualType NTTPType,
+ SourceLocation Loc) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Can't get a NULL template argument here");
+ break;
+
+ case TemplateArgument::Type:
+ return TemplateArgumentLoc(Arg,
+ S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
+
+ case TemplateArgument::Declaration: {
+ Expr *E
+ = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case TemplateArgument::Integral: {
+ Expr *E
+ = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
+ return TemplateArgumentLoc(TemplateArgument(E), E);
+ }
+
+ case TemplateArgument::Template:
+ return TemplateArgumentLoc(Arg, SourceRange(), Loc);
+
+ case TemplateArgument::Expression:
+ return TemplateArgumentLoc(Arg, Arg.getAsExpr());
+
+ case TemplateArgument::Pack:
+ return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
+ }
+
+ return TemplateArgumentLoc();
+}
+
+
+/// \brief Convert the given deduced template argument and add it to the set of
+/// fully-converted template arguments.
+static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
+ DeducedTemplateArgument Arg,
+ NamedDecl *Template,
+ QualType NTTPType,
+ TemplateDeductionInfo &Info,
+ bool InFunctionTemplate,
+ llvm::SmallVectorImpl<TemplateArgument> &Output) {
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ // This is a template argument pack, so check each of its arguments against
+ // the template parameter.
+ llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder;
+ for (TemplateArgument::pack_iterator PA = Arg.pack_begin(),
+ PAEnd = Arg.pack_end();
+ PA != PAEnd; ++PA) {
+ DeducedTemplateArgument InnerArg(*PA);
+ InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound());
+ if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template,
+ NTTPType, Info,
+ InFunctionTemplate, PackedArgsBuilder))
+ return true;
+ }
+
+ // Create the resulting argument pack.
+ TemplateArgument *PackedArgs = 0;
+ if (!PackedArgsBuilder.empty()) {
+ PackedArgs = new (S.Context) TemplateArgument[PackedArgsBuilder.size()];
+ std::copy(PackedArgsBuilder.begin(), PackedArgsBuilder.end(), PackedArgs);
+ }
+ Output.push_back(TemplateArgument(PackedArgs, PackedArgsBuilder.size()));
+ return false;
+ }
+
+ // Convert the deduced template argument into a template
+ // argument that we can check, almost as if the user had written
+ // the template argument explicitly.
+ TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType,
+ Info.getLocation());
+
+ // Check the template argument, converting it as necessary.
+ return S.CheckTemplateArgument(Param, ArgLoc,
+ Template,
+ Template->getLocation(),
+ Template->getSourceRange().getEnd(),
+ Output,
+ InFunctionTemplate
+ ? (Arg.wasDeducedFromArrayBound()
+ ? Sema::CTAK_DeducedFromArrayBound
+ : Sema::CTAK_Deduced)
+ : Sema::CTAK_Specified);
+}
+
/// Complete template argument deduction for a class template partial
/// specialization.
static Sema::TemplateDeductionResult
@@ -1333,12 +1441,32 @@
llvm::SmallVector<TemplateArgument, 4> Builder;
TemplateParameterList *PartialParams = Partial->getTemplateParameters();
for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
+ NamedDecl *Param = PartialParams->getParam(I);
if (Deduced[I].isNull()) {
- Info.Param = makeTemplateParameter(PartialParams->getParam(I));
+ Info.Param = makeTemplateParameter(Param);
return Sema::TDK_Incomplete;
}
- Builder.push_back(Deduced[I]);
+ // We have deduced this argument, so it still needs to be
+ // checked and converted.
+
+ // First, for a non-type template parameter type that is
+ // initialized by a declaration, we need the type of the
+ // corresponding non-type template parameter.
+ QualType NTTPType;
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ NTTPType = NTTP->getType();
+
+ if (ConvertDeducedTemplateArgument(S, Param, Deduced[I],
+ Partial, NTTPType, Info, false,
+ Builder)) {
+ Info.Param = makeTemplateParameter(Param);
+ // FIXME: These template arguments are temporary. Free them!
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
+ Builder.size()));
+ return Sema::TDK_SubstitutionFailure;
+ }
}
// Form the template argument list from the deduced template arguments.
@@ -1380,23 +1508,39 @@
llvm::SmallVector<TemplateArgument, 4> ConvertedInstArgs;
if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(),
- InstArgs, false, ConvertedInstArgs))
+ InstArgs, false, ConvertedInstArgs))
return Sema::TDK_SubstitutionFailure;
- for (unsigned I = 0, E = ConvertedInstArgs.size(); I != E; ++I) {
+ TemplateParameterList *TemplateParams
+ = ClassTemplate->getTemplateParameters();
+ for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
TemplateArgument InstArg = ConvertedInstArgs.data()[I];
- Decl *Param = const_cast<NamedDecl *>(
- ClassTemplate->getTemplateParameters()->getParam(I));
+ Decl *Param = TemplateParams->getParam(I);
- if (InstArg.getKind() == TemplateArgument::Expression) {
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
// When the argument is an expression, check the expression result
// against the actual template parameter to get down to the canonical
// template argument.
- // FIXME: Variadic templates.
- Expr *InstExpr = InstArg.getAsExpr();
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ Expr *InstExpr = 0;
+ if (InstArg.getKind() == TemplateArgument::Expression)
+ InstExpr = InstArg.getAsExpr();
+ else if (InstArg.getKind() == TemplateArgument::Integral) {
+ ExprResult InstExprFromArg
+ = S.BuildExpressionFromIntegralTemplateArgument(InstArg,
+ Info.getLocation());
+ if (InstExprFromArg.isInvalid()) {
+ Info.Param = makeTemplateParameter(Param);
+ Info.FirstArg = InstArg;
+ return Sema::TDK_SubstitutionFailure;
+ }
+
+ InstExpr = InstExprFromArg.get();
+ }
+
+ if (InstExpr) {
+ // FIXME: Variadic templates.
if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Partial->getTemplateArgs()[I];
@@ -1615,109 +1759,6 @@
return TDK_Success;
}
-/// \brief Allocate a TemplateArgumentLoc where all locations have
-/// been initialized to the given location.
-///
-/// \param S The semantic analysis object.
-///
-/// \param The template argument we are producing template argument
-/// location information for.
-///
-/// \param NTTPType For a declaration template argument, the type of
-/// the non-type template parameter that corresponds to this template
-/// argument.
-///
-/// \param Loc The source location to use for the resulting template
-/// argument.
-static TemplateArgumentLoc
-getTrivialTemplateArgumentLoc(Sema &S,
- const TemplateArgument &Arg,
- QualType NTTPType,
- SourceLocation Loc) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("Can't get a NULL template argument here");
- break;
-
- case TemplateArgument::Type:
- return TemplateArgumentLoc(Arg,
- S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
-
- case TemplateArgument::Declaration: {
- Expr *E
- = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
- .takeAs<Expr>();
- return TemplateArgumentLoc(TemplateArgument(E), E);
- }
-
- case TemplateArgument::Integral: {
- Expr *E
- = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>();
- return TemplateArgumentLoc(TemplateArgument(E), E);
- }
-
- case TemplateArgument::Template:
- return TemplateArgumentLoc(Arg, SourceRange(), Loc);
-
- case TemplateArgument::Expression:
- return TemplateArgumentLoc(Arg, Arg.getAsExpr());
-
- case TemplateArgument::Pack:
- return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo());
- }
-
- return TemplateArgumentLoc();
-}
-
-/// \brief Convert the given deduced template argument and add it to the set of
-/// fully-converted template arguments.
-static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
- DeducedTemplateArgument Arg,
- FunctionTemplateDecl *FunctionTemplate,
- QualType NTTPType,
- TemplateDeductionInfo &Info,
- llvm::SmallVectorImpl<TemplateArgument> &Output) {
- if (Arg.getKind() == TemplateArgument::Pack) {
- // This is a template argument pack, so check each of its arguments against
- // the template parameter.
- llvm::SmallVector<TemplateArgument, 2> PackedArgsBuilder;
- for (TemplateArgument::pack_iterator PA = Arg.pack_begin(),
- PAEnd = Arg.pack_end();
- PA != PAEnd; ++PA) {
- DeducedTemplateArgument InnerArg(*PA);
- InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound());
- if (ConvertDeducedTemplateArgument(S, Param, InnerArg, FunctionTemplate,
- NTTPType, Info, PackedArgsBuilder))
- return true;
- }
-
- // Create the resulting argument pack.
- TemplateArgument *PackedArgs = 0;
- if (!PackedArgsBuilder.empty()) {
- PackedArgs = new (S.Context) TemplateArgument[PackedArgsBuilder.size()];
- std::copy(PackedArgsBuilder.begin(), PackedArgsBuilder.end(), PackedArgs);
- }
- Output.push_back(TemplateArgument(PackedArgs, PackedArgsBuilder.size()));
- return false;
- }
-
- // Convert the deduced template argument into a template
- // argument that we can check, almost as if the user had written
- // the template argument explicitly.
- TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType,
- Info.getLocation());
-
- // Check the template argument, converting it as necessary.
- return S.CheckTemplateArgument(Param, ArgLoc,
- FunctionTemplate,
- FunctionTemplate->getLocation(),
- FunctionTemplate->getSourceRange().getEnd(),
- Output,
- Arg.wasDeducedFromArrayBound()
- ? Sema::CTAK_DeducedFromArrayBound
- : Sema::CTAK_Deduced);
-}
-
/// \brief Finish template argument deduction for a function template,
/// checking the deduced template arguments for completeness and forming
/// the function template specialization.
@@ -1791,7 +1832,7 @@
if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I],
FunctionTemplate, NTTPType, Info,
- Builder)) {
+ true, Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
@@ -2953,6 +2994,10 @@
if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
E = Expansion->getPattern();
+ // Skip through any implicit casts we added while type-checking.
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExpr();
+
// FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
// find other occurrences of template parameters.
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);