From 8918920a329506ea76693876cc8f23af145a6aaa Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Wed, 28 Aug 2013 23:48:32 +0000 Subject: [PATCH] Sema: Subst type default template args earlier Summary: We would not perform substitution at an appropriate point, allowing strange results to appear. We would accepts things that we shouldn't or mangle things incorrectly. Note that this hasn't fixed the other cases like template-template parameters or non-type template parameters. Reviewers: doug.gregor, rjmccall, rsmith Reviewed By: rsmith CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1507 llvm-svn: 189540 --- clang/lib/Sema/SemaTemplate.cpp | 73 +++++++++++-------- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 31 +++++++- clang/test/CodeGenCXX/mangle.cpp | 23 ++++++ .../SemaCXX/cxx1y-deduced-return-type.cpp | 9 +++ .../SemaTemplate/default-arguments-cxx0x.cpp | 31 ++++++++ clang/test/SemaTemplate/default-arguments.cpp | 28 +++++-- 6 files changed, 151 insertions(+), 44 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 4268aa24e368..426b13cfaf44 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2976,22 +2976,25 @@ SubstDefaultTemplateArgument(Sema &SemaRef, // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. if (ArgType->getType()->isDependentType()) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); - - MultiLevelTemplateArgumentList AllTemplateArgs - = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst) return 0; + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + + // Only substitute for the innermost template argument list. + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) + TemplateArgLists.addOuterTemplateArguments(None); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); - ArgType = SemaRef.SubstType(ArgType, AllTemplateArgs, - Param->getDefaultArgumentLoc(), - Param->getDeclName()); + ArgType = + SemaRef.SubstType(ArgType, TemplateArgLists, + Param->getDefaultArgumentLoc(), Param->getDeclName()); } return ArgType; @@ -3026,21 +3029,24 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, SmallVectorImpl &Converted) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); - - MultiLevelTemplateArgumentList AllTemplateArgs - = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst) return ExprError(); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + + // Only substitute for the innermost template argument list. + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) + TemplateArgLists.addOuterTemplateArguments(None); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); - return SemaRef.SubstExpr(Param->getDefaultArgument(), AllTemplateArgs); + return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); } /// \brief Substitute template arguments into the default template argument for @@ -3076,32 +3082,35 @@ SubstDefaultTemplateArgument(Sema &SemaRef, TemplateTemplateParmDecl *Param, SmallVectorImpl &Converted, NestedNameSpecifierLoc &QualifierLoc) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); - - MultiLevelTemplateArgumentList AllTemplateArgs - = SemaRef.getTemplateInstantiationArgs(Template, &TemplateArgs); - - Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Template, Converted, + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst) return TemplateName(); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + + // Only substitute for the innermost template argument list. + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) + TemplateArgLists.addOuterTemplateArguments(None); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); - // Substitute into the nested-name-specifier first, + // Substitute into the nested-name-specifier first, QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc(); if (QualifierLoc) { - QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, - AllTemplateArgs); + QualifierLoc = + SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgLists); if (!QualifierLoc) return TemplateName(); } - - return SemaRef.SubstTemplateName(QualifierLoc, - Param->getDefaultArgument().getArgument().getAsTemplate(), - Param->getDefaultArgument().getTemplateNameLoc(), - AllTemplateArgs); + + return SemaRef.SubstTemplateName( + QualifierLoc, + Param->getDefaultArgument().getArgument().getAsTemplate(), + Param->getDefaultArgument().getTemplateNameLoc(), + TemplateArgLists); } /// \brief If the given template parameter has a default template diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a797ae66b19b..5d6847fdf0ea 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1737,8 +1737,13 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->isParameterPack()); Inst->setAccess(AS_public); - if (D->hasDefaultArgument()) - Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); + if (D->hasDefaultArgument()) { + TypeSourceInfo *InstantiatedDefaultArg = + SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs, + D->getDefaultArgumentLoc(), D->getDeclName()); + if (InstantiatedDefaultArg) + Inst->setDefaultArgument(InstantiatedDefaultArg, false); + } // Introduce this template parameter's instantiation into the instantiation // scope. @@ -1888,7 +1893,11 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (Invalid) Param->setInvalidDecl(); - Param->setDefaultArgument(D->getDefaultArgument(), false); + if (D->hasDefaultArgument()) { + ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs); + if (!Value.isInvalid()) + Param->setDefaultArgument(Value.get(), false); + } // Introduce this template parameter's instantiation into the instantiation // scope. @@ -2011,7 +2020,21 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); - Param->setDefaultArgument(D->getDefaultArgument(), false); + if (D->hasDefaultArgument()) { + NestedNameSpecifierLoc QualifierLoc = + D->getDefaultArgument().getTemplateQualifierLoc(); + QualifierLoc = + SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); + TemplateName TName = SemaRef.SubstTemplateName( + QualifierLoc, D->getDefaultArgument().getArgument().getAsTemplate(), + D->getDefaultArgument().getTemplateNameLoc(), TemplateArgs); + if (!TName.isNull()) + Param->setDefaultArgument( + TemplateArgumentLoc(TemplateArgument(TName), + D->getDefaultArgument().getTemplateQualifierLoc(), + D->getDefaultArgument().getTemplateNameLoc()), + false); + } Param->setAccess(AS_public); // Introduce this template parameter's instantiation into the instantiation diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp index a9daa0df6194..f03f499fe13f 100644 --- a/clang/test/CodeGenCXX/mangle.cpp +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -910,3 +910,26 @@ namespace test40 { }; void g() { f(); } } + +namespace test41 { + // CHECK: define linkonce_odr void @_ZN6test414funcINS_1XEEEvNS_3fooILi20ES1_EE + template struct foo { + template friend void func(foo x) {} + }; + + struct X {}; + + void g() { func(foo<20, X>()); } +} + +namespace test42 { + // CHECK: define linkonce_odr void @_ZN6test424funcINS_1XEEEvNS_3fooILi20ES1_EE + template class T> struct foo { + template