summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-12-27 07:56:27 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-12-27 07:56:27 +0000
commit0e617ecdd115984ce6729554e17ea20a2783194f (patch)
tree77c399296d5527dc2f9b725c035c59a1e7773a06 /clang/lib/Sema/SemaTemplate.cpp
parent625038d5d5f406385f44983ac2a442b20ad7b241 (diff)
downloadbcm5719-llvm-0e617ecdd115984ce6729554e17ea20a2783194f.tar.gz
bcm5719-llvm-0e617ecdd115984ce6729554e17ea20a2783194f.zip
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
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp47
1 files changed, 45 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 8b8ab4a6e16..b335e7e2602 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2624,6 +2624,36 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
return TemplateArgs;
}
+template<typename PartialSpecDecl>
+static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
+ if (Partial->getDeclContext()->isDependentContext())
+ return;
+
+ // FIXME: Get the TDK from deduction in order to provide better diagnostics
+ // for non-substitution-failure issues?
+ TemplateDeductionInfo Info(Partial->getLocation());
+ if (S.isMoreSpecializedThanPrimary(Partial, Info))
+ return;
+
+ auto *Template = Partial->getSpecializedTemplate();
+ S.Diag(Partial->getLocation(),
+ diag::err_partial_spec_not_more_specialized_than_primary)
+ << /*variable template*/isa<VarTemplateDecl>(Template);
+
+ if (Info.hasSFINAEDiagnostic()) {
+ PartialDiagnosticAt Diag = {SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()};
+ Info.takeSFINAEDiagnostic(Diag);
+ SmallString<128> SFINAEArgString;
+ Diag.second.EmitToString(S.getDiagnostics(), SFINAEArgString);
+ S.Diag(Diag.first,
+ diag::note_partial_spec_not_more_specialized_than_primary)
+ << SFINAEArgString;
+ }
+
+ S.Diag(Template->getLocation(), diag::note_template_decl_here);
+}
+
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
TemplateParameterList *TemplateParams, StorageClass SC,
@@ -2749,6 +2779,11 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
PrevPartial->setMemberSpecialization();
+ // C++1z [temp.class.spec]p8: (DR1495)
+ // - The specialization shall be more specialized than the primary
+ // template (14.5.5.2).
+ checkMoreSpecializedThanPrimary(*this, Partial);
+
// Check that all of the template parameters of the variable template
// partial specialization are deducible from the template
// arguments. If not, this variable template partial specialization
@@ -5041,7 +5076,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CTAK == CTAK_Deduced &&
!Context.hasSameType(ParamType.getNonLValueExprType(Context),
- Arg->getType().getNonLValueExprType(Context))) {
+ Arg->getType())) {
// C++ [temp.deduct.type]p17: (DR1770)
// If P has a form that contains <i>, and if the type of i differs from
// the type of the corresponding template parameter of the template named
@@ -5055,7 +5090,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// itself, and so strip off references before comparing types. It's
// not clear how this is supposed to work for references.
Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
- << Arg->getType().getUnqualifiedType()
+ << Arg->getType()
<< ParamType.getUnqualifiedType();
Diag(Param->getLocation(), diag::note_template_param_here);
return ExprError();
@@ -6501,6 +6536,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
//
// -- The argument list of the specialization shall not be identical
// to the implicit argument list of the primary template.
+ //
+ // This rule has since been removed, because it's redundant given DR1495,
+ // but we keep it because it produces better diagnostics and recovery.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
<< /*class template*/0 << (TUK == TUK_Definition)
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
@@ -6543,6 +6581,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
PrevPartial->setMemberSpecialization();
+ // C++1z [temp.class.spec]p8: (DR1495)
+ // - The specialization shall be more specialized than the primary
+ // template (14.5.5.2).
+ checkMoreSpecializedThanPrimary(*this, Partial);
+
// Check that all of the template parameters of the class template
// partial specialization are deducible from the template
// arguments. If not, this class template partial specialization
OpenPOWER on IntegriCloud