Before checking a template template argument against its corresponding
template template parameter, substitute any prior template arguments
into the template template parameter. This, for example, allows us to
properly check the template template argument for a class such as:
template<typename T, template<T Value> class X> struct Foo;
The actual implementation of this feature was trivial; most of the
change is dedicated to giving decent diagnostics when this
substitution goes horribly wrong. We now get a note like:
note: while substituting prior template arguments into template
template parameter 'X' [with T = float]
As part of this change, enabled some very pedantic checking when
comparing template template parameter lists, which shook out a bug in
our overly-eager checking of default arguments of template template
parameters. We now perform only minimal checking of such default
arguments when they are initially parsed.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86864 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 6c88995..b2e0751 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2650,6 +2650,11 @@
std::string
getTemplateArgumentBindingsText(const TemplateParameterList *Params,
const TemplateArgumentList &Args);
+
+ std::string
+ getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgument *Args,
+ unsigned NumArgs);
/// \brief Describes the result of template argument deduction.
///
@@ -2872,17 +2877,26 @@
/// partial specialization or a function template. The
/// Entity is either a ClassTemplatePartialSpecializationDecl or
/// a FunctionTemplateDecl.
- DeducedTemplateArgumentSubstitution
+ DeducedTemplateArgumentSubstitution,
+
+ /// We are substituting prior template arguments into a new
+ /// template parameter. The template parameter itself is either a
+ /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
+ PriorTemplateArgumentSubstitution
} Kind;
/// \brief The point of instantiation within the source code.
SourceLocation PointOfInstantiation;
+ /// \brief The template in which we are performing the instantiation,
+ /// for substitutions of prior template arguments.
+ TemplateDecl *Template;
+
/// \brief The entity that is being instantiated.
uintptr_t Entity;
- // \brief If this the instantiation of a default template
- // argument, the list of template arguments.
+ /// \brief The list of template arguments we are substituting, if they
+ /// are not part of the entity.
const TemplateArgument *TemplateArgs;
/// \brief The number of template arguments in TemplateArgs.
@@ -2893,8 +2907,9 @@
/// template instantiation.
SourceRange InstantiationRange;
- ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Entity(0),
- TemplateArgs(0), NumTemplateArgs(0) {}
+ ActiveTemplateInstantiation()
+ : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0),
+ NumTemplateArgs(0) {}
friend bool operator==(const ActiveTemplateInstantiation &X,
const ActiveTemplateInstantiation &Y) {
@@ -2908,6 +2923,12 @@
case TemplateInstantiation:
return true;
+ case PriorTemplateArgumentSubstitution:
+ if (X.Template != Y.Template)
+ return false;
+
+ // Fall through
+
case DefaultTemplateArgumentInstantiation:
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
@@ -2993,6 +3014,22 @@
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
+ /// \brief Note that we are substituting prior template arguments into a
+ /// non-type or template template parameter.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ NonTypeTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
+ SourceRange InstantiationRange);
+
/// \brief Note that we have finished instantiating this template.
void Clear();