diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-02-09 00:54:43 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-02-09 00:54:43 +0000 |
commit | be9778d3046b54d4b399b3f4523b12c3286da474 (patch) | |
tree | f0c4fccd410ef1c9c0dfd45b3823a5cbae40b3b5 /lib/Sema/SemaTemplate.cpp | |
parent | c174fe5f125f749eaf5ea7cc41f3cbf049bc5ada (diff) |
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
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 125 |
1 files changed, 94 insertions, 31 deletions
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<DependencyChecker> { 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<DependencyChecker> { } } - 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<DependencyChecker> { bool TraverseTemplateName(TemplateName N) { if (TemplateTemplateParmDecl *PD = dyn_cast_or_null<TemplateTemplateParmDecl>(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<NonTypeTemplateParmDecl>(E->getDecl())) { - if (PD->getDepth() == Depth) { - Match = true; + dyn_cast<NonTypeTemplateParmDecl>(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<TemplateArgument> &TemplateArgs); + Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams, + unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &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<template<typename> class X> struct A { + // template<typename T, X<T> N> struct B; + // template<typename T> struct B<T, 0>; + // }; + // template<typename> using X = int; + // A<X>::B<int, 0> 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<TemplateArgument> &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; |