From: Richard Smith Date: Thu, 16 Feb 2017 00:36:47 +0000 (+0000) Subject: [c++1z] Diagnose non-deducible template parameters in deduction guide templates,... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=73de459c12741844e4f72a5cc6929a4a66a93cb5;p=clang [c++1z] Diagnose non-deducible template parameters in deduction guide templates, per [temp.param]p11. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@295264 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 41a149005d..6049d488de 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2002,6 +2002,10 @@ def err_deduction_guide_explicit_mismatch : Error< "previous declaration was%select{ not|}0">; def err_deduction_guide_specialized : Error<"deduction guide cannot be " "%select{explicitly instantiated|explicitly specialized}0">; +def err_deduction_guide_template_not_deducible : Error< + "deduction guide template contains " + "%select{a template parameter|template parameters}0 that cannot be " + "deduced">; // C++1y deduced return types def err_auto_fn_deduction_failure : Error< @@ -4146,7 +4150,7 @@ def ext_partial_specs_not_deducible : ExtWarn< "%select{a template parameter|template parameters}1 that cannot be " "deduced; this partial specialization will never be used">, DefaultError, InGroup>; -def note_partial_spec_unused_parameter : Note< +def note_non_deducible_parameter : Note< "non-deducible template parameter %0">; def err_partial_spec_ordering_ambiguous : Error< "ambiguous partial specializations of %0">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index dcb6c73523..2d37ed2cde 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5624,6 +5624,7 @@ public: Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); void CheckDeductionGuideDeclarator(Declarator &D, QualType &R, StorageClass &SC); + void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD); void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ff3909fd84..3905348d3c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9152,13 +9152,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } else if (CXXConversionDecl *Conversion = dyn_cast(NewFD)) { ActOnConversionDeclarator(Conversion); - } else if (NewFD->isDeductionGuide() && - NewFD->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization) { + } else if (NewFD->isDeductionGuide()) { + if (auto *TD = NewFD->getDescribedFunctionTemplate()) + CheckDeductionGuideTemplate(TD); + // A deduction guide is not on the list of entities that can be // explicitly specialized. - Diag(NewFD->getLocStart(), diag::err_deduction_guide_specialized) - << /*explicit specialization*/ 1; + if (NewFD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + Diag(NewFD->getLocStart(), diag::err_deduction_guide_specialized) + << /*explicit specialization*/ 1; } // Find any virtual functions that this function overrides. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index fd66c79865..5470017303 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3162,6 +3162,23 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { S.Diag(Template->getLocation(), diag::note_template_decl_here); } +static void +noteNonDeducibleParameters(Sema &S, TemplateParameterList *TemplateParams, + const llvm::SmallBitVector &DeducibleParams) { + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast(TemplateParams->getParam(I)); + if (Param->getDeclName()) + S.Diag(Param->getLocation(), diag::note_non_deducible_parameter) + << Param->getDeclName(); + else + S.Diag(Param->getLocation(), diag::note_non_deducible_parameter) + << "(anonymous)"; + } + } +} + + template static void checkTemplatePartialSpecialization(Sema &S, PartialSpecDecl *Partial) { @@ -3189,19 +3206,7 @@ static void checkTemplatePartialSpecialization(Sema &S, << (NumNonDeducible > 1) << SourceRange(Partial->getLocation(), Partial->getTemplateArgsAsWritten()->RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast(TemplateParams->getParam(I)); - if (Param->getDeclName()) - S.Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - S.Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } + noteNonDeducibleParameters(S, TemplateParams, DeducibleParams); } } @@ -3215,6 +3220,29 @@ void Sema::CheckTemplatePartialSpecialization( checkTemplatePartialSpecialization(*this, Partial); } +void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) { + // C++1z [temp.param]p11: + // A template parameter of a deduction guide template that does not have a + // default-argument shall be deducible from the parameter-type-list of the + // deduction guide template. + auto *TemplateParams = TD->getTemplateParameters(); + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + MarkDeducedTemplateParameters(TD, DeducibleParams); + for (unsigned I = 0; I != TemplateParams->size(); ++I) { + // A parameter pack is deducible (to an empty pack). + auto *Param = TemplateParams->getParam(I); + if (Param->isParameterPack() || hasVisibleDefaultArgument(Param)) + DeducibleParams[I] = true; + } + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count(); + Diag(TD->getLocation(), diag::err_deduction_guide_template_not_deducible) + << (NumNonDeducible > 1); + noteNonDeducibleParameters(*this, TemplateParams, DeducibleParams); + } +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, diff --git a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index 011130d0e7..3d256aa670 100644 --- a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -150,3 +150,21 @@ namespace look_into_current_instantiation { C c = {1, 2}; } + +namespace nondeducible { + template struct X {}; + + template // expected-note {{non-deducible template parameter 'A'}} + X() -> X; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}} + + template // expected-note {{non-deducible template parameter 'A'}} + X(typename X::type) -> X; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}} + + template // expected-note {{non-deducible template parameter 'B'}} + X(int) -> X; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}} + + template + X(float) -> X; // ok +} diff --git a/www/cxx_status.html b/www/cxx_status.html index 6216a81645..6cb87a8bc2 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -684,11 +684,10 @@ as the draft C++1z standard evolves. Template argument deduction for class templates P0091R3 - SVN + SVN P0512R0 - SVN Non-type template parameters with auto type