diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-06-20 19:49:13 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-06-20 19:49:13 +0000 |
commit | 07ed9cfc3e8db2d6acf2412bc138d61e88ccc5f5 (patch) | |
tree | 4c38e7c51bc560d6994f559fb0a15cd08130f26d /clang/lib/Sema/SemaTemplate.cpp | |
parent | 97dc622ab3f77d877ee302908dec20d9dbddfe2b (diff) | |
download | bcm5719-llvm-07ed9cfc3e8db2d6acf2412bc138d61e88ccc5f5.tar.gz bcm5719-llvm-07ed9cfc3e8db2d6acf2412bc138d61e88ccc5f5.zip |
Fix crash and rejects-valid when a later template parameter or default
template argument contains a backreference to a dependently-typed
earlier parameter.
In a case like:
template<typename T, T A, decltype(A) = A> struct X {};
template<typename U> auto Y = X<U, 0>();
we previously treated both references to `A` in the third parameter as
being of type `int` when checking the template-id in `Y`. That`s wrong;
the type of `A` in these contexts is the dependent type `U`.
When we encounter a non-type template argument that we can't convert to
the parameter type because of type-dependence, we now insert a dependent
conversion node so that the SubstNonTypeTemplateParmExpr for the
template argument will have the parameter's type rather than whatever
type the argument had.
llvm-svn: 363972
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 74a891bcb70..7b0a3a3e094 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4888,10 +4888,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); + + // If the parameter is a pack expansion, expand this slice of the pack. + if (auto *PET = NTTPType->getAs<PackExpansionType>()) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, + ArgumentPackIndex); + NTTPType = SubstType(PET->getPattern(), + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + } else { + NTTPType = SubstType(NTTPType, + MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), + NTTP->getDeclName()); + } + // If that worked, check the non-type template parameter type // for validity. if (!NTTPType.isNull()) @@ -6310,9 +6322,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // When checking a deduced template argument, deduce from its type even if // the type is dependent, in order to check the types of non-type template // arguments line up properly in partial ordering. - Optional<unsigned> Depth; - if (CTAK != CTAK_Specified) - Depth = Param->getDepth() + 1; + Optional<unsigned> Depth = Param->getDepth() + 1; if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), Arg, ParamType, Depth) == DAR_Failed) { @@ -6367,9 +6377,24 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. if (ParamType->isDependentType() || Arg->isTypeDependent()) { - // FIXME: Produce a cloned, canonical expression? - Converted = TemplateArgument(Arg); - return Arg; + // Force the argument to the type of the parameter to maintain invariants. + auto *PE = dyn_cast<PackExpansionExpr>(Arg); + if (PE) + Arg = PE->getPattern(); + ExprResult E = ImpCastExprToType( + Arg, ParamType.getNonLValueExprType(Context), CK_Dependent, + ParamType->isLValueReferenceType() ? VK_LValue : + ParamType->isRValueReferenceType() ? VK_XValue : VK_RValue); + if (E.isInvalid()) + return ExprError(); + if (PE) { + // Recreate a pack expansion if we unwrapped one. + E = new (Context) + PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(), + PE->getNumExpansions()); + } + Converted = TemplateArgument(E.get()); + return E; } // The initialization of the parameter from the argument is |