From 6493cc50b66c2d097b3e22514bbe303048c4a8ff Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 8 Nov 2010 17:16:59 +0000 Subject: [PATCH] Improve our handling of C++ [class.copy]p3, which specifies that a constructor template will not be used to copy a class object to a value of its own type. We were eliminating all constructor templates whose specializations look like a copy constructor, which eliminated important candidates. Fixes PR8182. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118418 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 4 +-- lib/AST/DeclCXX.cpp | 8 +---- lib/Sema/SemaInit.cpp | 38 +++++++++++++++++----- lib/Sema/SemaOverload.cpp | 2 +- test/SemaTemplate/constructor-template.cpp | 23 +++++++++++-- 5 files changed, 54 insertions(+), 21 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 3fc525e362..91653340aa 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1469,9 +1469,9 @@ public: bool isConvertingConstructor(bool AllowExplicit) const; /// \brief Determine whether this is a member template specialization that - /// looks like a copy constructor. Such constructors are never used to copy + /// would copy the object to itself. Such constructors are never used to copy /// an object. - bool isCopyConstructorLikeSpecialization() const; + bool isSpecializationCopyingObject() const; // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 17f2dfda64..bcb47baa24 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1176,7 +1176,7 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } -bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { +bool CXXConstructorDecl::isSpecializationCopyingObject() const { if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || (getPrimaryTemplate() == 0) || @@ -1188,12 +1188,6 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { ASTContext &Context = getASTContext(); CanQualType ParamType = Context.getCanonicalType(Param->getType()); - // Strip off the lvalue reference, if any. - if (CanQual ParamRefType - = ParamType->getAs()) - ParamType = ParamRefType->getPointeeType(); - - // Is it the same as our our class type? CanQualType ClassTy = Context.getCanonicalType(Context.getTagDeclType(getParent())); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index f45893df86..e601a7d328 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3391,17 +3391,39 @@ static ExprResult CopyObject(Sema &S, OverloadCandidateSet CandidateSet(Loc); for (llvm::tie(Con, ConEnd) = S.LookupConstructors(Class); Con != ConEnd; ++Con) { - // Only consider copy constructors. - CXXConstructorDecl *Constructor = dyn_cast(*Con); - if (!Constructor || Constructor->isInvalidDecl() || - !Constructor->isCopyConstructor() || - !Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) + // Only consider copy constructors and constructor templates. + CXXConstructorDecl *Constructor = 0; + + if ((Constructor = dyn_cast(*Con))) { + // Handle copy constructors, only. + if (!Constructor || Constructor->isInvalidDecl() || + !Constructor->isCopyConstructor() || + !Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) + continue; + + DeclAccessPair FoundDecl + = DeclAccessPair::make(Constructor, Constructor->getAccess()); + S.AddOverloadCandidate(Constructor, FoundDecl, + &CurInitExpr, 1, CandidateSet); + continue; + } + + // Handle constructor templates. + FunctionTemplateDecl *ConstructorTmpl = cast(*Con); + if (ConstructorTmpl->isInvalidDecl()) + continue; + + Constructor = cast( + ConstructorTmpl->getTemplatedDecl()); + if (!Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) continue; + // FIXME: Do we need to limit this to copy-constructor-like + // candidates? DeclAccessPair FoundDecl - = DeclAccessPair::make(Constructor, Constructor->getAccess()); - S.AddOverloadCandidate(Constructor, FoundDecl, - &CurInitExpr, 1, CandidateSet); + = DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess()); + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, 0, + &CurInitExpr, 1, CandidateSet, true); } OverloadCandidateSet::iterator Best; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 3ed79fd461..440f5acdbc 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3457,7 +3457,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // of a class object to an object of its class type. QualType ClassType = Context.getTypeDeclType(Constructor->getParent()); if (NumArgs == 1 && - Constructor->isCopyConstructorLikeSpecialization() && + Constructor->isSpecializationCopyingObject() && (Context.hasSameUnqualifiedType(ClassType, Args[0]->getType()) || IsDerivedFrom(Args[0]->getType(), ClassType))) return; diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index b6ca72e9e1..cf3fdfb7c1 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -71,16 +71,16 @@ struct X3 { template<> X3::X3(X3); // expected-error{{must pass its first argument by reference}} struct X4 { - X4(); // expected-note{{candidate constructor}} + X4(); ~X4(); - X4(X4&); // expected-note {{candidate constructor}} + X4(X4&); template X4(const T&, int = 17); }; X4 test_X4(bool Cond, X4 x4) { X4 a(x4, 17); // okay, constructor template X4 b(x4); // okay, copy constructor - return X4(); // expected-error{{no matching constructor}} + return X4(); } // Instantiation of a non-dependent use of a constructor @@ -109,3 +109,20 @@ void test_X5_X6() { X5 tf; X5 tf2(tf); } + +namespace PR8182 { + struct foo { + foo(); + template foo(T&); + + private: + foo(const foo&); + }; + + void test_foo() { + foo f1; + foo f2(f1); + foo f3 = f1; + } + +} -- 2.40.0