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.

llvm-svn: 182072
This commit is contained in:
Richard Smith 2013-05-17 02:19:35 +00:00
parent fbe4d85035
commit 4c163a093f
3 changed files with 65 additions and 5 deletions

View File

@ -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();

View File

@ -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<CXXConstructorDecl *>(
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<CXXConstructorDecl>(
SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs));
if (!Inh)
return 0;
}
cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh);
}
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,

View File

@ -0,0 +1,28 @@
// RUN: %clang_cc1 -std=c++11 %s -verify
// expected-no-diagnostics
namespace PR15757 {
struct S {
};
template<typename X, typename Y> struct T {
template<typename A> T(X x, A &&a) {}
template<typename A> explicit T(A &&a)
noexcept(noexcept(T(X(), static_cast<A &&>(a))))
: T(X(), static_cast<A &&>(a)) {}
};
template<typename X, typename Y> struct U : T<X, Y> {
using T<X, Y>::T;
};
U<S, char> foo(char ch) { return U<S, char>(ch); }
int main() {
U<S, int> a(42);
U<S, char> b('4');
return 0;
}
}