diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-28 02:37:25 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-28 02:37:25 +0000 |
| commit | 57aae07b4a31a5843fc6c808855ba138d62e7f23 (patch) | |
| tree | 8528311cb0cc59c03065f0c638377cdba52e501c /clang/lib/Sema/SemaTemplate.cpp | |
| parent | 69c5cc69edc8e768fc79036bc51017eadc8234de (diff) | |
| download | bcm5719-llvm-57aae07b4a31a5843fc6c808855ba138d62e7f23.tar.gz bcm5719-llvm-57aae07b4a31a5843fc6c808855ba138d62e7f23.zip | |
DR1315: a non-type template argument in a partial specialization is permitted
to make reference to template parameters. This is only a partial
implementation; we retain the restriction that the argument must not be
type-dependent, since it's unclear how that would work given the existence of
other language rules requiring an exact type match in this context, even for
type-dependent cases (a question has been raised on the core reflector).
llvm-svn: 290647
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 234 |
1 files changed, 127 insertions, 107 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5a3083ce3bc..996a8baee1d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1638,12 +1638,22 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { typedef RecursiveASTVisitor<DependencyChecker> super; unsigned Depth; + + // Whether we're looking for a use of a template parameter that makes the + // overall construct type-dependent / a dependent type. This is strictly + // best-effort for now; we may fail to match at all for a dependent type + // in some cases if this is set. + bool IgnoreNonTypeDependent; + bool Match; SourceLocation MatchLoc; - DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {} + DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent) + : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent), + Match(false) {} - DependencyChecker(TemplateParameterList *Params) : Match(false) { + DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent) + : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) { NamedDecl *ND = Params->getParam(0); if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) { Depth = PD->getDepth(); @@ -1664,12 +1674,31 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { return false; } + bool TraverseStmt(Stmt *S, DataRecursionQueue *Q = nullptr) { + // Prune out non-type-dependent expressions if requested. This can + // sometimes result in us failing to find a template parameter reference + // (if a value-dependent expression creates a dependent type), but this + // mode is best-effort only. + if (auto *E = dyn_cast_or_null<Expr>(S)) + if (IgnoreNonTypeDependent && !E->isTypeDependent()) + return true; + return super::TraverseStmt(S, Q); + } + + bool TraverseTypeLoc(TypeLoc TL) { + if (IgnoreNonTypeDependent && !TL.isNull() && + !TL.getType()->isDependentType()) + return true; + return super::TraverseTypeLoc(TL); + } + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc()); } bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - return !Matches(T->getDepth()); + // For a best-effort search, keep looking until we find a location. + return IgnoreNonTypeDependent || !Matches(T->getDepth()); } bool TraverseTemplateName(TemplateName N) { @@ -1707,7 +1736,7 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { /// list. static bool DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { - DependencyChecker Checker(Params); + DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false); Checker.TraverseType(T); return Checker.Match; } @@ -2539,10 +2568,6 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } -static bool CheckTemplatePartialSpecializationArgs( - Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams, - unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &TemplateArgs); - static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, NamedDecl *PrevDecl, SourceLocation Loc, @@ -2654,6 +2679,59 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { S.Diag(Template->getLocation(), diag::note_template_decl_here); } +template<typename PartialSpecDecl> +static void checkTemplatePartialSpecialization(Sema &S, + PartialSpecDecl *Partial) { + // C++1z [temp.class.spec]p8: (DR1495) + // - The specialization shall be more specialized than the primary + // template (14.5.5.2). + checkMoreSpecializedThanPrimary(S, Partial); + + // C++ [temp.class.spec]p8: (DR1315) + // - Each template-parameter shall appear at least once in the + // template-id outside a non-deduced context. + // C++1z [temp.class.spec.match]p3 (P0127R2) + // If the template arguments of a partial specialization cannot be + // deduced because of the structure of its template-parameter-list + // and the template-id, the program is ill-formed. + auto *TemplateParams = Partial->getTemplateParameters(); + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + S.MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count(); + S.Diag(Partial->getLocation(), diag::ext_partial_specs_not_deducible) + << isa<VarTemplatePartialSpecializationDecl>(Partial) + << (NumNonDeducible > 1) + << SourceRange(Partial->getLocation(), + Partial->getTemplateArgsAsWritten()->RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(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)"; + } + } + } +} + +void Sema::CheckTemplatePartialSpecialization( + ClassTemplatePartialSpecializationDecl *Partial) { + checkTemplatePartialSpecialization(*this, Partial); +} + +void Sema::CheckTemplatePartialSpecialization( + VarTemplatePartialSpecializationDecl *Partial) { + checkTemplatePartialSpecialization(*this, Partial); +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, @@ -2703,11 +2781,12 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // Find the variable template (partial) specialization declaration that // corresponds to these arguments. if (IsPartialSpecialization) { - if (CheckTemplatePartialSpecializationArgs( - *this, TemplateNameLoc, VarTemplate->getTemplateParameters(), - TemplateArgs.size(), Converted)) + if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate, + TemplateArgs.size(), Converted)) return true; + // FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we + // also do them during instantiation. bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( @@ -2779,37 +2858,7 @@ 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 - // will never be used. - llvm::SmallBitVector DeducibleParams(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, - TemplateParams->getDepth(), DeducibleParams); - - if (!DeducibleParams.all()) { - unsigned NumNonDeducible = - DeducibleParams.size() - DeducibleParams.count(); - Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) - << /*variable template*/ 1 << (NumNonDeducible > 1) - << SourceRange(TemplateNameLoc, RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } - } + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. @@ -6208,12 +6257,12 @@ static bool CheckTemplateSpecializationScope(Sema &S, return false; } -static SourceRange findTemplateParameter(unsigned Depth, Expr *E) { - if (!E->isInstantiationDependent()) +static SourceRange findTemplateParameterInType(unsigned Depth, Expr *E) { + if (!E->isTypeDependent()) return SourceLocation(); - DependencyChecker Checker(Depth); + DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true); Checker.TraverseStmt(E); - if (Checker.Match && Checker.MatchLoc.isInvalid()) + if (Checker.MatchLoc.isInvalid()) return E->getSourceRange(); return Checker.MatchLoc; } @@ -6221,9 +6270,9 @@ static SourceRange findTemplateParameter(unsigned Depth, Expr *E) { static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) { if (!TL.getType()->isDependentType()) return SourceLocation(); - DependencyChecker Checker(Depth); + DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true); Checker.TraverseTypeLoc(TL); - if (Checker.Match && Checker.MatchLoc.isInvalid()) + if (Checker.MatchLoc.isInvalid()) return TL.getSourceRange(); return Checker.MatchLoc; } @@ -6275,8 +6324,16 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( // shall not involve a template parameter of the partial // specialization except when the argument expression is a // simple identifier. + // -- The type of a template parameter corresponding to a + // specialized non-type argument shall not be dependent on a + // parameter of the specialization. + // DR1315 removes the first bullet, leaving an incoherent set of rules. + // We implement a compromise between the original rules and DR1315: + // -- A specialized non-type template argument shall not be + // type-dependent and the corresponding template parameter + // shall have a non-dependent type. SourceRange ParamUseRange = - findTemplateParameter(Param->getDepth(), ArgExpr); + findTemplateParameterInType(Param->getDepth(), ArgExpr); if (ParamUseRange.isValid()) { if (IsDefaultArgument) { S.Diag(TemplateNameLoc, @@ -6292,26 +6349,15 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( 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. - // - // 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()); + 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; + << Param->getType(); S.Diag(Param->getLocation(), diag::note_template_param_here) - << (IsDefaultArgument ? ParamUseRange : SourceRange()); + << (IsDefaultArgument ? ParamUseRange : SourceRange()) + << ParamUseRange; return true; } } @@ -6330,20 +6376,25 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( /// partial specialization. /// /// \returns \c true if there was an error, \c false otherwise. -static bool CheckTemplatePartialSpecializationArgs( - Sema &S, SourceLocation TemplateNameLoc, - TemplateParameterList *TemplateParams, unsigned NumExplicit, - SmallVectorImpl<TemplateArgument> &TemplateArgs) { - const TemplateArgument *ArgList = TemplateArgs.data(); +bool Sema::CheckTemplatePartialSpecializationArgs( + SourceLocation TemplateNameLoc, TemplateDecl *PrimaryTemplate, + unsigned NumExplicit, ArrayRef<TemplateArgument> TemplateArgs) { + // We have to be conservative when checking a template in a dependent + // context. + if (PrimaryTemplate->getDeclContext()->isDependentContext()) + return false; + TemplateParameterList *TemplateParams = + PrimaryTemplate->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NonTypeTemplateParmDecl *Param = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); if (!Param) continue; - if (CheckNonTypeTemplatePartialSpecializationArgs( - S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit)) + if (CheckNonTypeTemplatePartialSpecializationArgs(*this, TemplateNameLoc, + Param, &TemplateArgs[I], + 1, I >= NumExplicit)) return true; } @@ -6487,11 +6538,12 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - if (CheckTemplatePartialSpecializationArgs( - *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(), - TemplateArgs.size(), Converted)) + if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate, + TemplateArgs.size(), Converted)) return true; + // FIXME: Move this to CheckTemplatePartialSpecializationArgs so we + // also do it during instantiation. bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( @@ -6581,39 +6633,7 @@ 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 - // will never be used. - llvm::SmallBitVector DeducibleParams(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, - TemplateParams->getDepth(), - DeducibleParams); - - if (!DeducibleParams.all()) { - unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count(); - Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) - << /*class template*/0 << (NumNonDeducible > 1) - << SourceRange(TemplateNameLoc, RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } - } + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. |

