From: Richard Smith Date: Fri, 17 May 2013 02:19:35 +0000 (+0000) Subject: PR15757: When we instantiate an inheriting constructor template, also X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b5eb3f5bf383807103dc1377a124fd96ee21d02a;p=clang PR15757: When we instantiate an inheriting constructor template, also instantiate the inherited constructor template and mark that as the constructor which the instantiated specialization is inheriting. This fixes a crash-on-valid when trying to compute the exception specification of a specialization of the inheriting constructor. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182072 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index 6e054c463a..f9481c6c0c 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -94,17 +94,23 @@ namespace clang { /// \brief Add a new outermost level to the multi-level template argument /// list. void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { - TemplateArgumentLists.push_back(ArgList(TemplateArgs->data(), - TemplateArgs->size())); + addOuterTemplateArguments(ArgList(TemplateArgs->data(), + TemplateArgs->size())); } /// \brief Add a new outmost level to the multi-level template argument /// list. void addOuterTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { - TemplateArgumentLists.push_back(ArgList(Args, NumArgs)); + addOuterTemplateArguments(ArgList(Args, NumArgs)); } - + + /// \brief Add a new outmost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(ArgList Args) { + TemplateArgumentLists.push_back(Args); + } + /// \brief Retrieve the innermost template argument list. const ArgList &getInnermost() const { return TemplateArgumentLists.front(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ff59cdcbc4..09ddd9db65 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1558,10 +1558,36 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); + // Claim that the instantiation of a constructor or constructor template // inherits the same constructor that the template does. - if (const CXXConstructorDecl *Inh = Constructor->getInheritedConstructor()) + if (CXXConstructorDecl *Inh = const_cast( + Constructor->getInheritedConstructor())) { + // If we're instantiating a specialization of a function template, our + // "inherited constructor" will actually itself be a function template. + // Instantiate a declaration of it, too. + if (FunctionTemplate) { + assert(!TemplateParams && Inh->getDescribedFunctionTemplate() && + !Inh->getParent()->isDependentContext() && + "inheriting constructor template in dependent context?"); + Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(), + Inh); + if (Inst) + return 0; + Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext()); + LocalInstantiationScope LocalScope(SemaRef); + + // Use the same template arguments that we deduced for the inheriting + // constructor. There's no way they could be deduced differently. + MultiLevelTemplateArgumentList InheritedArgs; + InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost()); + Inh = cast_or_null( + SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs)); + if (!Inh) + return 0; + } cast(Method)->setInheritedConstructor(Inh); + } } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, diff --git a/test/SemaCXX/cxx11-inheriting-ctors.cpp b/test/SemaCXX/cxx11-inheriting-ctors.cpp new file mode 100644 index 0000000000..67d55213a0 --- /dev/null +++ b/test/SemaCXX/cxx11-inheriting-ctors.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify + +// expected-no-diagnostics + +namespace PR15757 { + struct S { + }; + + template struct T { + template T(X x, A &&a) {} + + template explicit T(A &&a) + noexcept(noexcept(T(X(), static_cast(a)))) + : T(X(), static_cast(a)) {} + }; + + template struct U : T { + using T::T; + }; + + U foo(char ch) { return U(ch); } + + int main() { + U a(42); + U b('4'); + return 0; + } +}