[c++17] Implement P0522R0 as written. This allows a template template argument
to be specified for a template template parameter whenever the parameter is at
least as specialized as the argument (when there's an obvious and correct
mapping from uses of the parameter to uses of the argument). For example, a
template with more parameters can be passed to a template template parameter
with fewer, if those trailing parameters have default arguments.
This is disabled by default, despite being a DR resolution, as it's fairly
broken in its current state: there are no partial ordering rules to cope with
template template parameters that have different parameter lists, meaning that
code that attempts to decompose template-ids based on arity can hit unavoidable
ambiguity issues.
The diagnostics produced on a non-matching argument are also pretty bad right
now, but I aim to improve them in a subsequent commit.
llvm-svn: 290792
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ec2f598..facc5d1 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5585,6 +5585,10 @@
return Arg;
}
+static void DiagnoseTemplateParameterListArityMismatch(
+ Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
+ Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
+
/// \brief Check a template argument against its corresponding
/// template template parameter.
///
@@ -5601,6 +5605,9 @@
return false;
}
+ if (Template->isInvalidDecl())
+ return true;
+
// C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be
// the name of a class template or an alias template, expressed as an
@@ -5628,6 +5635,25 @@
if (Param->isExpandedParameterPack())
Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
+ // C++1z [temp.arg.template]p3: (DR 150)
+ // A template-argument matches a template template-parameter P when P
+ // is at least as specialized as the template-argument A.
+ if (getLangOpts().RelaxedTemplateTemplateArgs) {
+ // Quick check for the common case:
+ // If P contains a parameter pack, then A [...] matches P if each of A's
+ // template parameters matches the corresponding template parameter in
+ // the template-parameter-list of P.
+ if (TemplateParameterListsAreEqual(
+ Template->getTemplateParameters(), Params, false,
+ TPL_TemplateTemplateArgumentMatch, Arg.getLocation()))
+ return false;
+
+ if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
+ Arg.getLocation()))
+ return false;
+ // FIXME: Produce better diagnostics for deduction failures.
+ }
+
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
Params,
true,
@@ -5839,7 +5865,7 @@
return false;
}
- // Check that both are parameter packs are neither are parameter packs.
+ // Check that both are parameter packs or neither are parameter packs.
// However, if we are matching a template template argument to a
// template template parameter, the template template parameter can have
// a parameter pack where the template template argument does not.