From dec06664a1c4d8984251083db2215875aea1c80d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 21 Aug 2009 18:42:58 +0000 Subject: Introduce support for constructor templates, which can now be declared and will participate in overload resolution. Unify the instantiation of CXXMethodDecls and CXXConstructorDecls, which had already gotten out-of-sync. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79658 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 2 + lib/AST/DeclCXX.cpp | 12 ++++ lib/Parse/ParseDecl.cpp | 5 +- lib/Sema/SemaDeclCXX.cpp | 19 ++++- lib/Sema/SemaOverload.cpp | 59 ++++++++-------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 96 ++++++++++---------------- test/SemaTemplate/constructor-template.cpp | 24 +++++++ test/SemaTemplate/member-function-template.cpp | 2 +- 8 files changed, 127 insertions(+), 92 deletions(-) create mode 100644 test/SemaTemplate/constructor-template.cpp diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 327f9ff622..bffedfcd78 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -161,6 +161,8 @@ public: OverloadIterator(OverloadedFunctionDecl *Ovl) : D(Ovl), Iter(Ovl->function_begin()) { } + OverloadIterator(NamedDecl *ND); + reference operator*() const; pointer operator->() const { return (**this).get(); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b126a09fc4..5c0bbec1ff 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -712,6 +712,18 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, return new (C) OverloadedFunctionDecl(DC, N); } +OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) { + if (!ND) + return; + + if (isa(ND) || isa(ND)) + D = ND; + else if (OverloadedFunctionDecl *Ovl = dyn_cast(ND)) { + D = ND; + Iter = Ovl->function_begin(); + } +} + void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) { Functions.push_back(F); this->setLocation(F.get()->getLocation()); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d3d2cf06e3..597d43fb1b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -844,7 +844,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // being defined and the next token is a '(', then this is a // constructor declaration. We're done with the decl-specifiers // and will treat this token as an identifier. - if (getLang().CPlusPlus && CurScope->isClassScope() && + if (getLang().CPlusPlus && + (CurScope->isClassScope() || + (CurScope->isTemplateParamScope() && + CurScope->getParent()->isClassScope())) && Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && NextToken().getKind() == tok::l_paren) goto DoneWithDeclSpec; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 15d32b08a7..5de302e174 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2599,11 +2599,24 @@ Sema::PerformInitializationByConstructor(QualType ClassType, DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { - CXXConstructorDecl *Constructor = cast(*Con); + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl= dyn_cast(*Con); + if (ConstructorTmpl) + Constructor + = cast(ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast(*Con); + if ((Kind == IK_Direct) || (Kind == IK_Copy && Constructor->isConvertingConstructor()) || - (Kind == IK_Default && Constructor->isDefaultConstructor())) - AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + (Kind == IK_Default && Constructor->isDefaultConstructor())) { + if (ConstructorTmpl) + AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, + Args, NumArgs, CandidateSet); + else + AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } } // FIXME: When we decide not to synthesize the implicitly-declared diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 21196d9cfa..f21b38a649 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1343,11 +1343,27 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType, for (llvm::tie(Con, ConEnd) = ToRecordDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { - CXXConstructorDecl *Constructor = cast(*Con); + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast(*Con); + if (ConstructorTmpl) + Constructor + = cast(ConstructorTmpl->getTemplatedDecl()); + else + Constructor = cast(*Con); + if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor()) - AddOverloadCandidate(Constructor, &From, 1, CandidateSet, - /*SuppressUserConversions=*/true, ForceRValue); + Constructor->isConvertingConstructor()) { + if (ConstructorTmpl) + AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From, + 1, CandidateSet, + /*SuppressUserConversions=*/true, + ForceRValue); + else + AddOverloadCandidate(Constructor, &From, 1, CandidateSet, + /*SuppressUserConversions=*/true, ForceRValue); + } } } } @@ -4324,29 +4340,18 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, OverloadCandidateSet CandidateSet; DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName(); - if (OverloadedFunctionDecl *Ovl - = dyn_cast(MemExpr->getMemberDecl())) { - for (OverloadedFunctionDecl::function_iterator - Func = Ovl->function_begin(), - FuncEnd = Ovl->function_end(); - Func != FuncEnd; ++Func) { - if ((Method = dyn_cast(*Func))) - AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, - /*SuppressUserConversions=*/false); - else - AddMethodTemplateCandidate(cast(*Func), - /*FIXME:*/false, /*FIXME:*/0, - /*FIXME:*/0, ObjectArg, Args, NumArgs, - CandidateSet, - /*SuppressUsedConversions=*/false); - } - } else - AddMethodTemplateCandidate( - cast(MemExpr->getMemberDecl()), - /*FIXME:*/false, /*FIXME:*/0, - /*FIXME:*/0, ObjectArg, Args, NumArgs, - CandidateSet, - /*SuppressUsedConversions=*/false); + for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd; + Func != FuncEnd; ++Func) { + if ((Method = dyn_cast(*Func))) + AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, + /*SuppressUserConversions=*/false); + else + AddMethodTemplateCandidate(cast(*Func), + /*FIXME:*/false, /*FIXME:*/0, + /*FIXME:*/0, ObjectArg, Args, NumArgs, + CandidateSet, + /*SuppressUsedConversions=*/false); + } OverloadCandidateSet::iterator Best; switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 078c32b439..9e05b3231e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -485,10 +485,25 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { // Build the instantiated method declaration. CXXRecordDecl *Record = cast(Owner); - CXXMethodDecl *Method - = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), - D->getDeclName(), T, D->getDeclaratorInfo(), - D->isStatic(), D->isInline()); + CXXMethodDecl *Method = 0; + + DeclarationName Name = D->getDeclName(); + CXXConstructorDecl *ConstructorD = dyn_cast(D); + if (ConstructorD) { + QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); + Name = SemaRef.Context.DeclarationNames.getCXXConstructorName( + SemaRef.Context.getCanonicalType(ClassTy)); + Method = CXXConstructorDecl::Create(SemaRef.Context, Record, + ConstructorD->getLocation(), + Name, T, + ConstructorD->getDeclaratorInfo(), + ConstructorD->isExplicit(), + ConstructorD->isInline(), false); + } else { + Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), + D->getDeclName(), T, D->getDeclaratorInfo(), + D->isStatic(), D->isInline()); + } if (!FunctionTemplate) Method->setInstantiationOfMemberFunction(D); @@ -507,15 +522,20 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { if (InitMethodInstantiation(Method, D)) Method->setInvalidDecl(); - NamedDecl *PrevDecl - = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(), - 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; + NamedDecl *PrevDecl = 0; + + if (!FunctionTemplate) { + 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; SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, @@ -528,60 +548,16 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { &TemplateArgs, InsertPos); else if (!Method->isInvalidDecl() || !PrevDecl) - Owner->addDecl(Method); + Owner->addDecl(Method); + return Method; } Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) { - // FIXME: Look for existing, explicit specializations. - Sema::LocalInstantiationScope Scope(SemaRef); - - 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( - SemaRef.Context.getCanonicalType(ClassTy)); - CXXConstructorDecl *Constructor - = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), - Name, T, D->getDeclaratorInfo(), - D->isExplicit(), D->isInline(), false); - Constructor->setInstantiationOfMemberFunction(D); - - // Attach the parameters - for (unsigned P = 0; P < Params.size(); ++P) - Params[P]->setOwningFunction(Constructor); - Constructor->setParams(SemaRef.Context, Params.data(), 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; - SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); - - Record->addedConstructor(SemaRef.Context, Constructor); - Owner->addDecl(Constructor); - return Constructor; + return VisitCXXMethodDecl(D); } Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) { - // FIXME: Look for existing, explicit specializations. Sema::LocalInstantiationScope Scope(SemaRef); llvm::SmallVector Params; diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp new file mode 100644 index 0000000000..14df2e2632 --- /dev/null +++ b/test/SemaTemplate/constructor-template.cpp @@ -0,0 +1,24 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct X0 { // expected-note{{candidate}} + X0(int); // expected-note{{candidate}} + template X0(T); + template X0(T*, U*); +}; + +void accept_X0(X0); + +void test_X0(int i, float f) { + X0 x0a(i); + X0 x0b(f); + X0 x0c = i; + X0 x0d = f; + accept_X0(i); + accept_X0(&i); + accept_X0(f); + accept_X0(&f); + X0 x0e(&i, &f); + X0 x0f(&f, &i); + + X0 x0g(f, &i); // expected-error{{no matching constructor}} +} diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp index 0f3a37a702..906980ac11 100644 --- a/test/SemaTemplate/member-function-template.cpp +++ b/test/SemaTemplate/member-function-template.cpp @@ -27,4 +27,4 @@ void test_X_f1(X x, int i, float f) { int &ir1 = x.f1(i); int &ir2 = x.f1(f, i); int &ir3 = x.f1(i, i); -} \ No newline at end of file +} -- cgit v1.2.3