DR1495: A partial specialization is ill-formed if it is not (strictly) more
specialized than the primary template. (Put another way, if we imagine there
were a partial specialization matching the primary template, we should never
select it if some other partial specialization also matches.)
llvm-svn: 290593
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 0e20ef2..d10b0c9 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1972,8 +1972,14 @@
/// \brief Determine whether two template arguments are the same.
static bool isSameTemplateArg(ASTContext &Context,
- const TemplateArgument &X,
- const TemplateArgument &Y) {
+ TemplateArgument X,
+ const TemplateArgument &Y,
+ bool PackExpansionMatchesPack = false) {
+ // If we're checking deduced arguments (X) against original arguments (Y),
+ // we will have flattened packs to non-expansions in X.
+ if (PackExpansionMatchesPack && X.isPackExpansion() && !Y.isPackExpansion())
+ X = X.getPackExpansionPattern();
+
if (X.getKind() != Y.getKind())
return false;
@@ -2016,7 +2022,7 @@
XPEnd = X.pack_end(),
YP = Y.pack_begin();
XP != XPEnd; ++XP, ++YP)
- if (!isSameTemplateArg(Context, *XP, *YP))
+ if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack))
return false;
return true;
@@ -2400,6 +2406,48 @@
return Sema::TDK_Success;
}
+/// Complete template argument deduction for a class or variable template,
+/// when partial ordering against a partial specialization.
+// FIXME: Factor out duplication with partial specialization version above.
+Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
+ Sema &S, TemplateDecl *Template, bool PartialOrdering,
+ const TemplateArgumentList &TemplateArgs,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ TemplateDeductionInfo &Info) {
+ // Unevaluated SFINAE context.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
+ Sema::SFINAETrap Trap(S);
+
+ Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template));
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ SmallVector<TemplateArgument, 4> Builder;
+ if (auto Result = ConvertDeducedTemplateArguments(
+ S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder))
+ return Result;
+
+ // Check that we produced the correct argument list.
+ TemplateParameterList *TemplateParams = Template->getTemplateParameters();
+ for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
+ TemplateArgument InstArg = Builder[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
+ /*PackExpansionMatchesPack*/true)) {
+ Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
+ Info.FirstArg = TemplateArgs[I];
+ Info.SecondArg = InstArg;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ }
+
+ if (Trap.hasErrorOccurred())
+ return Sema::TDK_SubstitutionFailure;
+
+ return Sema::TDK_Success;
+}
+
+
/// \brief Perform template argument deduction to determine whether
/// the given template arguments match the given class template
/// partial specialization per C++ [temp.class.spec.match].
@@ -4535,14 +4583,13 @@
/// specialized than another, P2.
///
/// \tparam PartialSpecializationDecl The kind of P2, which must be a
-/// {Class,Var}TemplatePartialSpecializationDecl.
+/// {Class,Var}Template{PartialSpecialization,}Decl.
/// \param T1 The injected-class-name of P1 (faked for a variable template).
/// \param T2 The injected-class-name of P2 (faked for a variable template).
-/// \param Loc The location at which the comparison is required.
template<typename PartialSpecializationDecl>
static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
PartialSpecializationDecl *P2,
- SourceLocation Loc) {
+ TemplateDeductionInfo &Info) {
// C++ [temp.class.order]p1:
// For two class template partial specializations, the first is at least as
// specialized as the second if, given the following rewrite to two
@@ -4568,7 +4615,6 @@
// template partial specialization's template arguments, for
// example.
SmallVector<DeducedTemplateArgument, 4> Deduced;
- TemplateDeductionInfo Info(Loc);
// Determine whether P1 is at least as specialized as P2.
Deduced.resize(P2->getTemplateParameters()->size());
@@ -4579,7 +4625,8 @@
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
Deduced.end());
- Sema::InstantiatingTemplate Inst(S, Loc, P2, DeducedArgs, Info);
+ Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs,
+ Info);
auto *TST1 = T1->castAs<TemplateSpecializationType>();
if (FinishTemplateArgumentDeduction(
S, P2, /*PartialOrdering=*/true,
@@ -4609,8 +4656,9 @@
QualType PT1 = PS1->getInjectedSpecializationType();
QualType PT2 = PS2->getInjectedSpecializationType();
- bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc);
- bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc);
+ TemplateDeductionInfo Info(Loc);
+ bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
if (Better1 == Better2)
return nullptr;
@@ -4618,6 +4666,20 @@
return Better1 ? PS1 : PS2;
}
+bool Sema::isMoreSpecializedThanPrimary(
+ ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
+ ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
+ QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
+ QualType PartialT = Spec->getInjectedSpecializationType();
+ if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
+ return false;
+ if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
+ Info.clearSFINAEDiagnostic();
+ return false;
+ }
+ return true;
+}
+
VarTemplatePartialSpecializationDecl *
Sema::getMoreSpecializedPartialSpecialization(
VarTemplatePartialSpecializationDecl *PS1,
@@ -4634,8 +4696,9 @@
QualType PT2 = Context.getTemplateSpecializationType(
CanonTemplate, PS2->getTemplateArgs().asArray());
- bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc);
- bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc);
+ TemplateDeductionInfo Info(Loc);
+ bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
if (Better1 == Better2)
return nullptr;
@@ -4643,6 +4706,30 @@
return Better1 ? PS1 : PS2;
}
+bool Sema::isMoreSpecializedThanPrimary(
+ VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
+ TemplateDecl *Primary = Spec->getSpecializedTemplate();
+ // FIXME: Cache the injected template arguments rather than recomputing
+ // them for each partial specialization.
+ SmallVector<TemplateArgument, 8> PrimaryArgs;
+ Context.getInjectedTemplateArgs(Primary->getTemplateParameters(),
+ PrimaryArgs);
+
+ TemplateName CanonTemplate =
+ Context.getCanonicalTemplateName(TemplateName(Primary));
+ QualType PrimaryT = Context.getTemplateSpecializationType(
+ CanonTemplate, PrimaryArgs);
+ QualType PartialT = Context.getTemplateSpecializationType(
+ CanonTemplate, Spec->getTemplateArgs().asArray());
+ if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
+ return false;
+ if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
+ Info.clearSFINAEDiagnostic();
+ return false;
+ }
+ return true;
+}
+
static void
MarkUsedTemplateParameters(ASTContext &Ctx,
const TemplateArgument &TemplateArg,