diff options
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 141 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 | ||||
-rw-r--r-- | test/SemaTemplate/default-arguments.cpp | 51 |
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]; |