r201031 - PR16519, PR18009: When checking a partial specialization for uses of its own
Richard Smith
richard-llvm at metafoo.co.uk
Sat Feb 8 16:54:43 PST 2014
Author: rsmith
Date: Sat Feb 8 18:54:43 2014
New Revision: 201031
URL: http://llvm.org/viewvc/llvm-project?rev=201031&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaTemplate/class-template-spec.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=201031&r1=201030&r2=201031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Feb 8 18:54:43 2014
@@ -3202,9 +3202,13 @@ def err_default_arg_in_partial_spec : Er
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 "
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=201031&r1=201030&r2=201031&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Feb 8 18:54:43 2014
@@ -1488,6 +1488,9 @@ struct DependencyChecker : RecursiveASTV
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 : RecursiveASTV
}
}
- 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 : RecursiveASTV
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(
}
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::ActOnVarTemplateSpecial
// 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 CheckTemplateSpecializationS
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 CheckNonTypeTemplatePartialS
// 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 CheckNonTypeTemplatePartialS
/// \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 CheckTemplatePartialSpeciali
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(S
// corresponds to these arguments.
if (isPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(
- *this, ClassTemplate->getTemplateParameters(), Converted))
+ *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(),
+ TemplateArgs.size(), Converted))
return true;
bool InstantiationDependent;
Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=201031&r1=201030&r2=201031&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Sat Feb 8 18:54:43 2014
@@ -119,3 +119,61 @@ namespace rdar9676205 {
};
}
+
+namespace PR18009 {
+ template <typename T> struct A {
+ template <int N, int M> struct S;
+ template <int N> struct S<N, sizeof(T)> {};
+ };
+ A<int>::S<8, sizeof(int)> a; // ok
+
+ template <typename T> struct B {
+ template <int N, int M> struct S; // expected-note {{declared here}}
+ template <int N> struct S<N, sizeof(T) +
+ N // expected-error {{non-type template argument depends on a template parameter of the partial specialization}}
+ > {};
+ };
+ B<int>::S<8, sizeof(int) + 8> s; // expected-error {{undefined}}
+
+ template<int A> struct outer {
+ template<int B, int C> struct inner {};
+ template<int C> struct inner<A * 2, C> {};
+ };
+}
+
+namespace PR16519 {
+ template<typename T, T...N> struct integer_sequence { typedef T value_type; }; // expected-warning {{extension}}
+
+ template<typename T> struct __make_integer_sequence;
+ template<typename T, T N> using make_integer_sequence = typename __make_integer_sequence<T>::template make<N, N % 2>::type; // expected-warning {{extension}}
+
+ template<typename T, typename T::value_type ...Extra> struct __make_integer_sequence_impl; // expected-warning {{extension}}
+ template<typename T, T ...N, T ...Extra> struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> { // expected-warning 2{{extension}}
+ typedef integer_sequence<T, N..., sizeof...(N) + N..., Extra...> type;
+ };
+
+ template<typename T> struct __make_integer_sequence {
+ template<T N, T Parity, typename = void> struct make;
+ template<typename Dummy> struct make<0, 0, Dummy> { typedef integer_sequence<T> type; };
+ template<typename Dummy> struct make<1, 1, Dummy> { typedef integer_sequence<T, 0> type; };
+ template<T N, typename Dummy> struct make<N, 0, Dummy> : __make_integer_sequence_impl<make_integer_sequence<T, N/2> > {};
+ template<T N, typename Dummy> struct make<N, 1, Dummy> : __make_integer_sequence_impl<make_integer_sequence<T, N/2>, N - 1> {};
+ };
+
+ using X = make_integer_sequence<int, 5>; // expected-warning {{extension}}
+ using X = integer_sequence<int, 0, 1, 2, 3, 4>; // expected-warning {{extension}}
+}
+
+namespace DefaultArgVsPartialSpec {
+ // Check that the diagnostic points at the partial specialization, not just at
+ // the default argument.
+ template<typename T, int N =
+ sizeof(T) // expected-note {{template parameter is used in default argument declared here}}
+ > struct X {};
+ template<typename T> struct X<T> {}; // expected-error {{non-type template argument depends on a template parameter of the partial specialization}}
+
+ template<typename T,
+ T N = 0 // expected-note {{template parameter is declared here}}
+ > struct S;
+ template<typename T> struct S<T> {}; // expected-error {{non-type template argument specializes a template parameter with dependent type 'T'}}
+}
More information about the cfe-commits
mailing list