diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-27 07:56:27 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-27 07:56:27 +0000 |
| commit | 0e617ecdd115984ce6729554e17ea20a2783194f (patch) | |
| tree | 77c399296d5527dc2f9b725c035c59a1e7773a06 /clang/lib/Sema/SemaTemplate.cpp | |
| parent | 625038d5d5f406385f44983ac2a442b20ad7b241 (diff) | |
| download | bcm5719-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.cpp | 47 |
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 |

