From: Douglas Gregor Date: Tue, 24 Mar 2009 16:43:20 +0000 (+0000) Subject: Template instantiation for constructors X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=615c5d4674355ba830b9978f462ca7a8c5d15f85;p=clang Template instantiation for constructors git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67623 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 89805a84ac..f21a462e66 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1654,6 +1654,8 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc, return; } + // FIXME: Need to handle dependent types and expressions here. + // We will treat direct-initialization as a copy-initialization: // int x(1); -as-> int x = 1; // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); @@ -1672,6 +1674,13 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc, if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) DeclInitType = Array->getElementType(); + // FIXME: This isn't the right place to complete the type. + if (RequireCompleteType(VDecl->getLocation(), VDecl->getType(), + diag::err_typecheck_decl_incomplete_type)) { + VDecl->setInvalidDecl(); + return; + } + if (VDecl->getType()->isRecordType()) { CXXConstructorDecl *Constructor = PerformInitializationByConstructor(DeclInitType, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 685b9cfd5b..4738dfbd8e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -44,6 +44,7 @@ namespace { Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitCXXMethodDecl(CXXMethodDecl *D); + Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); @@ -247,6 +248,50 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { return Method; } +Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + llvm::SmallVector Params; + QualType T = InstantiateFunctionType(D, Params); + if (T.isNull()) + return 0; + + // Build the instantiated method declaration. + CXXRecordDecl *Record = cast(Owner); + QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); + DeclarationName Name + = SemaRef.Context.DeclarationNames.getCXXConstructorName(ClassTy); + CXXConstructorDecl *Constructor + = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), + Name, T, D->isExplicit(), D->isInline(), + false); + + // Attach the parameters + for (unsigned P = 0; P < Params.size(); ++P) + Params[P]->setOwningFunction(Constructor); + Constructor->setParams(SemaRef.Context, &Params[0], Params.size()); + + if (InitMethodInstantiation(Constructor, D)) + Constructor->setInvalidDecl(); + + NamedDecl *PrevDecl + = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true); + + // In C++, the previous declaration we find might be a tag type + // (class or enum). In this case, the new declaration will hide the + // tag type. Note that this does does not apply if we're declaring a + // typedef (C++ [dcl.typedef]p4). + if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag) + PrevDecl = 0; + bool Redeclaration = false; + bool OverloadableAttrRequired = false; + if (SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, + /*FIXME:*/OverloadableAttrRequired)) + Constructor->setInvalidDecl(); + + if (!Constructor->isInvalidDecl()) + Owner->addDecl(Constructor); + return Constructor; +} + Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { llvm::SmallVector Params; QualType T = InstantiateFunctionType(D, Params); diff --git a/test/SemaTemplate/instantiate-method.cpp b/test/SemaTemplate/instantiate-method.cpp index 5baf2ad1b2..3a52c62d69 100644 --- a/test/SemaTemplate/instantiate-method.cpp +++ b/test/SemaTemplate/instantiate-method.cpp @@ -41,9 +41,23 @@ void test_ovl_bad() { template class HasDestructor { +public: virtual ~HasDestructor() = 0; }; int i = sizeof(HasDestructor); // FIXME: forces instantiation, but // the code below should probably instantiate by itself. int abstract_destructor[__is_abstract(HasDestructor)? 1 : -1]; + + +template +class Constructors { +public: + Constructors(const T&); + Constructors(const Constructors &other); +}; + +void test_constructors() { + Constructors ci1(17); + Constructors ci2 = ci1; +}