Check that template template arguments match template template parameters
properly even when a non-type template parameter has a dependent type.
Previously, if a non-type template parameter was dependent, but not dependent
on an outer level of template parameter, we would not match the type of the
parameter. Under [temp.arg.template], we are supposed to check that the types
are equivalent, which means checking for syntactic equivalence in the dependent
case.
This also fixes some accepts-invalids when passing templates with auto-typed
non-type template parameters as template template arguments.
llvm-svn: 291512
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 795e602..fd086a4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1653,6 +1653,7 @@
typedef RecursiveASTVisitor<DependencyChecker> super;
unsigned Depth;
+ bool FindLessThanDepth;
// Whether we're looking for a use of a template parameter that makes the
// overall construct type-dependent / a dependent type. This is strictly
@@ -1663,25 +1664,16 @@
bool Match;
SourceLocation MatchLoc;
- DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent)
- : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent),
- Match(false) {}
+ DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent,
+ bool FindLessThanDepth = false)
+ : Depth(Depth), FindLessThanDepth(FindLessThanDepth),
+ IgnoreNonTypeDependent(IgnoreNonTypeDependent), 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();
- } else if (NonTypeTemplateParmDecl *PD =
- dyn_cast<NonTypeTemplateParmDecl>(ND)) {
- Depth = PD->getDepth();
- } else {
- Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth();
- }
- }
+ : DependencyChecker(Params->getDepth(), IgnoreNonTypeDependent) {}
bool Matches(unsigned ParmDepth, SourceLocation Loc = SourceLocation()) {
- if (ParmDepth >= Depth) {
+ if (FindLessThanDepth ^ (ParmDepth >= Depth)) {
Match = true;
MatchLoc = Loc;
return true;
@@ -5838,6 +5830,15 @@
return E;
}
+static bool isDependentOnOuter(NonTypeTemplateParmDecl *NTTP) {
+ if (NTTP->getDepth() == 0 || !NTTP->getType()->isDependentType())
+ return false;
+ DependencyChecker Checker(NTTP->getDepth(), /*IgnoreNonTypeDependent*/ false,
+ /*FindLessThanDepth*/ true);
+ Checker.TraverseType(NTTP->getType());
+ return Checker.Match;
+}
+
/// \brief Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
bool Complain,
@@ -5894,11 +5895,10 @@
// If we are matching a template template argument to a template
// template parameter and one of the non-type template parameter types
- // is dependent, then we must wait until template instantiation time
- // to actually compare the arguments.
+ // is dependent on an outer template's parameter, then we must wait until
+ // template instantiation time to actually compare the arguments.
if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
- (OldNTTP->getType()->isDependentType() ||
- NewNTTP->getType()->isDependentType()))
+ (isDependentOnOuter(OldNTTP) || isDependentOnOuter(NewNTTP)))
return true;
if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {