|
@@ -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;
|