When performing template argument deduction to select a partial

specialization while substituting a partial template parameter pack,
don't try to extend the existing deduction.

This caused us to select the wrong partial specialization in some rare
cases. A recent change to libc++ caused this to happen in practice for
code using std::conjunction.
This commit is contained in:
Richard Smith 2021-05-05 14:44:49 -07:00
parent 909a5ccf3b
commit 6bbfa0fd40
2 changed files with 30 additions and 0 deletions

View File

@ -3079,6 +3079,10 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
// This deduction has no relation to any outer instantiation we might be
// performing.
LocalInstantiationScope InstantiationScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result
@ -3127,6 +3131,10 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial,
*this, Sema::ExpressionEvaluationContext::Unevaluated);
SFINAETrap Trap(*this);
// This deduction has no relation to any outer instantiation we might be
// performing.
LocalInstantiationScope InstantiationScope(*this);
SmallVector<DeducedTemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
if (TemplateDeductionResult Result = ::DeduceTemplateArguments(

View File

@ -112,3 +112,25 @@ namespace InstantiationDependent {
_Static_assert(!A<X>::specialized, "");
_Static_assert(A<Y>::specialized, "");
}
namespace IgnorePartialSubstitution {
template <typename... T> struct tuple {}; // expected-warning 0-1{{extension}}
template <typename> struct IsTuple {
enum { value = false };
};
template <typename... Us> struct IsTuple<tuple<Us...> > { // expected-warning 0-1{{extension}}
enum { value = true };
};
template <bool...> using ignore = void; // expected-warning 0-2{{extension}}
template <class... Pred> ignore<Pred::value...> helper(); // expected-warning 0-1{{extension}}
using S = IsTuple<tuple<int> >; // expected-warning 0-1{{extension}}
// This used to pick the primary template, because we got confused and
// thought that template parameter 0 was the current partially-substituted
// pack (from `helper`) during the deduction for the partial specialization.
void f() { helper<S>(); }
_Static_assert(S::value, "");
}