return false;
}
+/// \brief Substitute template arguments into the default template argument for
+/// the given template type parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the template template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static DeclaratorInfo *
+SubstDefaultTemplateArgument(Sema &SemaRef,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ TemplateTypeParmDecl *Param,
+ TemplateArgumentListBuilder &Converted) {
+ DeclaratorInfo *ArgType = Param->getDefaultArgumentInfo();
+
+ // If the argument type is dependent, instantiate it now based
+ // on the previously-computed template arguments.
+ if (ArgType->getType()->isDependentType()) {
+ TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+ /*TakeArgs=*/false);
+
+ MultiLevelTemplateArgumentList AllTemplateArgs
+ = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+ Template, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs,
+ Param->getDefaultArgumentLoc(),
+ Param->getDeclName());
+ }
+
+ return ArgType;
+}
+
+/// \brief Substitute template arguments into the default template argument for
+/// the given non-type template parameter.
+///
+/// \param SemaRef the semantic analysis object for which we are performing
+/// the substitution.
+///
+/// \param Template the template that we are synthesizing template arguments
+/// for.
+///
+/// \param TemplateLoc the location of the template name that started the
+/// template-id we are checking.
+///
+/// \param RAngleLoc the location of the right angle bracket ('>') that
+/// terminates the template-id.
+///
+/// \param Param the template template parameter whose default we are
+/// substituting into.
+///
+/// \param Converted the list of template arguments provided for template
+/// parameters that precede \p Param in the template parameter list.
+///
+/// \returns the substituted template argument, or NULL if an error occurred.
+static Sema::OwningExprResult
+SubstDefaultTemplateArgument(Sema &SemaRef,
+ TemplateDecl *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc,
+ NonTypeTemplateParmDecl *Param,
+ TemplateArgumentListBuilder &Converted) {
+ TemplateArgumentList TemplateArgs(SemaRef.Context, Converted,
+ /*TakeArgs=*/false);
+
+ MultiLevelTemplateArgumentList AllTemplateArgs
+ = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs);
+
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
+ Template, Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SourceRange(TemplateLoc, RAngleLoc));
+
+ return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs);
+}
+
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
if (!TTP->hasDefaultArgument())
break;
- DeclaratorInfo *ArgType = TTP->getDefaultArgumentInfo();
-
- // If the argument type is dependent, instantiate it now based
- // on the previously-computed template arguments.
- if (ArgType->getType()->isDependentType()) {
- InstantiatingTemplate Inst(*this, TemplateLoc,
- Template, Converted.getFlatArguments(),
- Converted.flatSize(),
- SourceRange(TemplateLoc, RAngleLoc));
-
- TemplateArgumentList TemplateArgs(Context, Converted,
- /*TakeArgs=*/false);
- ArgType = SubstType(ArgType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- TTP->getDefaultArgumentLoc(),
- TTP->getDeclName());
- }
-
+ DeclaratorInfo *ArgType = SubstDefaultTemplateArgument(*this,
+ Template,
+ TemplateLoc,
+ RAngleLoc,
+ TTP,
+ Converted);
if (!ArgType)
return true;
-
- Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()), ArgType);
+
+ Arg = TemplateArgumentLoc(TemplateArgument(ArgType->getType()),
+ ArgType);
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument())
break;
- InstantiatingTemplate Inst(*this, TemplateLoc,
- Template, Converted.getFlatArguments(),
- Converted.flatSize(),
- SourceRange(TemplateLoc, RAngleLoc));
-
- TemplateArgumentList TemplateArgs(Context, Converted,
- /*TakeArgs=*/false);
-
- Sema::OwningExprResult E
- = SubstExpr(NTTP->getDefaultArgument(),
- MultiLevelTemplateArgumentList(TemplateArgs));
+ Sema::OwningExprResult E = SubstDefaultTemplateArgument(*this, Template,
+ TemplateLoc,
+ RAngleLoc,
+ NTTP,
+ Converted);
if (E.isInvalid())
return true;
struct B<void> {
typedef B<void*> type;
};
+
+// Nested default arguments for template parameters.
+template<typename T> struct X1 { };
+
+template<typename T>
+struct X2 {
+ template<typename U = typename X1<T>::type> // expected-error{{no type named}}
+ struct Inner1 { };
+
+ template<T Value = X1<T>::value> // expected-error{{no member named 'value'}}
+ struct NonType1 { };
+
+ template<T Value>
+ struct Inner2 { };
+
+ template<typename U>
+ struct Inner3 {
+ template<typename X = T, typename V = U>
+ struct VeryInner { };
+
+ template<T Value1 = sizeof(T), T Value2 = sizeof(U),
+ T Value3 = Value1 + Value2>
+ struct NonType2 { };
+ };
+};
+
+X2<int> x2i;
+X2<int>::Inner1<float> x2iif;
+
+X2<int>::Inner1<> x2bad; // expected-note{{instantiation of default argument}}
+
+X2<int>::NonType1<'a'> x2_nontype1;
+X2<int>::NonType1<> x2_nontype1_bad; // expected-note{{instantiation of default argument}}
+
+// Check multi-level substitution into template type arguments
+X2<int>::Inner3<float>::VeryInner<> vi;
+X2<char>::Inner3<int>::NonType2<> x2_deep_nontype;
+
+
+template<typename T, typename U>
+struct is_same { static const bool value = false; };
+
+template<typename T>
+struct is_same<T, T> { static const bool value = true; };
+
+static int array1[is_same<__typeof__(vi),
+ X2<int>::Inner3<float>::VeryInner<int, float> >::value? 1 : -1];
+
+static int array2[is_same<__typeof(x2_deep_nontype),
+ X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int),
+ sizeof(char)+sizeof(int)> >::value? 1 : -1];