From be9778d3046b54d4b399b3f4523b12c3286da474 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 9 Feb 2014 00:54:43 +0000 Subject: [PATCH] PR16519, PR18009: When checking a partial specialization for uses of its own template parameters, don't look for parameters of outer templates. If a problem is found in a default template argument, point the diagnostic at the partial specialization (with a note pointing at the default argument) instead of pointing it at the default argument and leaving it unclear which partial specialization os problematic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201031 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 4 + lib/Sema/SemaTemplate.cpp | 125 ++++++++++++++++----- test/SemaTemplate/class-template-spec.cpp | 58 ++++++++++ 3 files changed, 156 insertions(+), 31 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b765677bdf..0e8e213dc9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3202,9 +3202,13 @@ def err_default_arg_in_partial_spec : Error< def err_dependent_non_type_arg_in_partial_spec : Error< "non-type template argument depends on a template parameter of the " "partial specialization">; +def note_dependent_non_type_default_arg_in_partial_spec : Note< + "template parameter is used in default argument declared here">; def err_dependent_typed_non_type_arg_in_partial_spec : Error< "non-type template argument specializes a template parameter with " "dependent type %0">; +def note_dependent_typed_non_type_default_arg_in_partial_spec : Note< + "template parameter is declared here">; def err_partial_spec_args_match_primary_template : Error< "%select{class|variable}0 template partial specialization does not " "specialize any template argument; to %select{declare|define}1 the " diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d24f7f01b8..7f6a7adc58 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1488,6 +1488,9 @@ struct DependencyChecker : RecursiveASTVisitor { unsigned Depth; bool Match; + SourceLocation MatchLoc; + + DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {} DependencyChecker(TemplateParameterList *Params) : Match(false) { NamedDecl *ND = Params->getParam(0); @@ -1501,14 +1504,20 @@ struct DependencyChecker : RecursiveASTVisitor { } } - bool Matches(unsigned ParmDepth) { + bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) { + llvm::errs() << "Found " << ParmDepth << " vs " << Depth << "\n"; if (ParmDepth >= Depth) { Match = true; + MatchLoc = Loc; return true; } return false; } + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc()); + } + bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) { return !Matches(T->getDepth()); } @@ -1516,21 +1525,28 @@ struct DependencyChecker : RecursiveASTVisitor { bool TraverseTemplateName(TemplateName N) { if (TemplateTemplateParmDecl *PD = dyn_cast_or_null(N.getAsTemplateDecl())) - if (Matches(PD->getDepth())) return false; + if (Matches(PD->getDepth())) + return false; return super::TraverseTemplateName(N); } bool VisitDeclRefExpr(DeclRefExpr *E) { if (NonTypeTemplateParmDecl *PD = - dyn_cast(E->getDecl())) { - if (PD->getDepth() == Depth) { - Match = true; + dyn_cast(E->getDecl())) + if (Matches(PD->getDepth(), E->getExprLoc())) return false; - } - } return super::VisitDeclRefExpr(E); } - + + bool VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + return TraverseType(T->getReplacementType()); + } + + bool + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) { + return TraverseTemplateArgument(T->getArgumentPack()); + } + bool TraverseInjectedClassNameType(const InjectedClassNameType *T) { return TraverseType(T->getInjectedSpecializationType()); } @@ -2267,8 +2283,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, } static bool CheckTemplatePartialSpecializationArgs( - Sema &S, TemplateParameterList *TemplateParams, - SmallVectorImpl &TemplateArgs); + Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams, + unsigned ExplicitArgs, SmallVectorImpl &TemplateArgs); static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, NamedDecl *PrevDecl, @@ -2401,7 +2417,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // corresponds to these arguments. if (IsPartialSpecialization) { if (CheckTemplatePartialSpecializationArgs( - *this, VarTemplate->getTemplateParameters(), Converted)) + *this, TemplateNameLoc, VarTemplate->getTemplateParameters(), + TemplateArgs.size(), Converted)) return true; bool InstantiationDependent; @@ -5679,15 +5696,36 @@ static bool CheckTemplateSpecializationScope(Sema &S, return false; } +static SourceRange findTemplateParameter(unsigned Depth, Expr *E) { + if (!E->isInstantiationDependent()) + return SourceLocation(); + DependencyChecker Checker(Depth); + Checker.TraverseStmt(E); + if (Checker.Match && Checker.MatchLoc.isInvalid()) + return E->getSourceRange(); + return Checker.MatchLoc; +} + +static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) { + if (!TL.getType()->isDependentType()) + return SourceLocation(); + DependencyChecker Checker(Depth); + Checker.TraverseTypeLoc(TL); + if (Checker.Match && Checker.MatchLoc.isInvalid()) + return TL.getSourceRange(); + return Checker.MatchLoc; +} + /// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs /// that checks non-type template partial specialization arguments. static bool CheckNonTypeTemplatePartialSpecializationArgs( - Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args, - unsigned NumArgs) { + Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param, + const TemplateArgument *Args, unsigned NumArgs, bool IsDefaultArgument) { for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].getKind() == TemplateArgument::Pack) { if (CheckNonTypeTemplatePartialSpecializationArgs( - S, Param, Args[I].pack_begin(), Args[I].pack_size())) + S, TemplateNameLoc, Param, Args[I].pack_begin(), + Args[I].pack_size(), IsDefaultArgument)) return true; continue; @@ -5725,22 +5763,43 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( // shall not involve a template parameter of the partial // specialization except when the argument expression is a // simple identifier. - if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) { - S.Diag(ArgExpr->getLocStart(), - diag::err_dependent_non_type_arg_in_partial_spec) - << ArgExpr->getSourceRange(); + SourceRange ParamUseRange = + findTemplateParameter(Param->getDepth(), ArgExpr); + if (ParamUseRange.isValid()) { + if (IsDefaultArgument) { + S.Diag(TemplateNameLoc, + diag::err_dependent_non_type_arg_in_partial_spec); + S.Diag(ParamUseRange.getBegin(), + diag::note_dependent_non_type_default_arg_in_partial_spec) + << ParamUseRange; + } else { + S.Diag(ParamUseRange.getBegin(), + diag::err_dependent_non_type_arg_in_partial_spec) + << ParamUseRange; + } return true; } // -- The type of a template parameter corresponding to a // specialized non-type argument shall not be dependent on a // parameter of the specialization. - if (Param->getType()->isDependentType()) { - S.Diag(ArgExpr->getLocStart(), - diag::err_dependent_typed_non_type_arg_in_partial_spec) - << Param->getType() - << ArgExpr->getSourceRange(); - S.Diag(Param->getLocation(), diag::note_template_param_here); + // + // FIXME: We need to delay this check until instantiation in some cases: + // + // template class X> struct A { + // template N> struct B; + // template struct B; + // }; + // template using X = int; + // A::B b; + ParamUseRange = findTemplateParameter( + Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc()); + if (ParamUseRange.isValid()) { + S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getLocStart(), + diag::err_dependent_typed_non_type_arg_in_partial_spec) + << Param->getType() << ParamUseRange; + S.Diag(Param->getLocation(), diag::note_template_param_here) + << (IsDefaultArgument ? ParamUseRange : SourceRange()); return true; } } @@ -5751,15 +5810,17 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( /// \brief Check the non-type template arguments of a class template /// partial specialization according to C++ [temp.class.spec]p9. /// +/// \param TemplateNameLoc the location of the template name. /// \param TemplateParams the template parameters of the primary class -/// template. -/// +/// template. +/// \param NumExplicit the number of explicitly-specified template arguments. /// \param TemplateArgs the template arguments of the class template -/// partial specialization. +/// partial specialization. /// -/// \returns true if there was an error, false otherwise. +/// \returns \c true if there was an error, \c false otherwise. static bool CheckTemplatePartialSpecializationArgs( - Sema &S, TemplateParameterList *TemplateParams, + Sema &S, SourceLocation TemplateNameLoc, + TemplateParameterList *TemplateParams, unsigned NumExplicit, SmallVectorImpl &TemplateArgs) { const TemplateArgument *ArgList = TemplateArgs.data(); @@ -5769,7 +5830,8 @@ static bool CheckTemplatePartialSpecializationArgs( if (!Param) continue; - if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1)) + if (CheckNonTypeTemplatePartialSpecializationArgs( + S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit)) return true; } @@ -5916,7 +5978,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // corresponds to these arguments. if (isPartialSpecialization) { if (CheckTemplatePartialSpecializationArgs( - *this, ClassTemplate->getTemplateParameters(), Converted)) + *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(), + TemplateArgs.size(), Converted)) return true; bool InstantiationDependent; diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index e82537abde..0292c1b8ff 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -119,3 +119,61 @@ namespace rdar9676205 { }; } + +namespace PR18009 { + template struct A { + template struct S; + template struct S {}; + }; + A::S<8, sizeof(int)> a; // ok + + template struct B { + template struct S; // expected-note {{declared here}} + template struct S {}; + }; + B::S<8, sizeof(int) + 8> s; // expected-error {{undefined}} + + template struct outer { + template struct inner {}; + template struct inner {}; + }; +} + +namespace PR16519 { + template struct integer_sequence { typedef T value_type; }; // expected-warning {{extension}} + + template struct __make_integer_sequence; + template using make_integer_sequence = typename __make_integer_sequence::template make::type; // expected-warning {{extension}} + + template struct __make_integer_sequence_impl; // expected-warning {{extension}} + template struct __make_integer_sequence_impl, Extra...> { // expected-warning 2{{extension}} + typedef integer_sequence type; + }; + + template struct __make_integer_sequence { + template struct make; + template struct make<0, 0, Dummy> { typedef integer_sequence type; }; + template struct make<1, 1, Dummy> { typedef integer_sequence type; }; + template struct make : __make_integer_sequence_impl > {}; + template struct make : __make_integer_sequence_impl, N - 1> {}; + }; + + using X = make_integer_sequence; // expected-warning {{extension}} + using X = integer_sequence; // expected-warning {{extension}} +} + +namespace DefaultArgVsPartialSpec { + // Check that the diagnostic points at the partial specialization, not just at + // the default argument. + template struct X {}; + template struct X {}; // expected-error {{non-type template argument depends on a template parameter of the partial specialization}} + + template struct S; + template struct S {}; // expected-error {{non-type template argument specializes a template parameter with dependent type 'T'}} +} -- 2.40.0