aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaTemplate.cpp141
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp11
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp14
-rw-r--r--test/SemaTemplate/default-arguments.cpp51
5 files changed, 175 insertions, 45 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b21315bf0e..b709fb84bc 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2844,7 +2844,8 @@ public:
// C++ Template Instantiation
//
- MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D);
+ MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D,
+ const TemplateArgumentList *Innermost = 0);
/// \brief A template instantiation that is currently in progress.
struct ActiveTemplateInstantiation {
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5ef370104d..0f7106135b 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1449,6 +1449,102 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
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,
@@ -1516,44 +1612,27 @@ 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;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 50070fc663..9e8dc2ea2c 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -28,11 +28,20 @@ using namespace clang;
/// \brief Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
+///
+/// \param D the declaration for which we are computing template instantiation
+/// arguments.
+///
+/// \param Innermost if non-NULL, the innermost template argument list.
MultiLevelTemplateArgumentList
-Sema::getTemplateInstantiationArgs(NamedDecl *D) {
+Sema::getTemplateInstantiationArgs(NamedDecl *D,
+ const TemplateArgumentList *Innermost) {
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
+ if (Innermost)
+ Result.addOuterTemplateArguments(Innermost);
+
DeclContext *Ctx = dyn_cast<DeclContext>(D);
if (!Ctx)
Ctx = D->getDeclContext();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 641ea24427..d37476259e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -923,18 +923,8 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->wasDeclaredWithTypename(),
D->isParameterPack());
- // FIXME: Do we actually want to perform substitution here? I don't think
- // we do.
- if (D->hasDefaultArgument()) {
- DeclaratorInfo *DefaultPattern = D->getDefaultArgumentInfo();
- DeclaratorInfo *DefaultInst
- = SemaRef.SubstType(DefaultPattern, TemplateArgs,
- D->getDefaultArgumentLoc(),
- D->getDeclName());
-
- Inst->setDefaultArgument(DefaultInst,
- D->defaultArgumentWasInherited() /* preserve? */);
- }
+ if (D->hasDefaultArgument())
+ Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
// Introduce this template parameter's instantiation into the instantiation
// scope.
diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp
index 33677aab73..fc3f9fe9b9 100644
--- a/test/SemaTemplate/default-arguments.cpp
+++ b/test/SemaTemplate/default-arguments.cpp
@@ -42,3 +42,54 @@ template<>
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];