forked from OSchip/llvm-project
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. llvm-svn: 118418
This commit is contained in:
parent
2cd1fd4a82
commit
bd6b17f4ef
|
@ -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()); }
|
||||
|
|
|
@ -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<LValueReferenceType> ParamRefType
|
||||
= ParamType->getAs<LValueReferenceType>())
|
||||
ParamType = ParamRefType->getPointeeType();
|
||||
|
||||
|
||||
// Is it the same as our our class type?
|
||||
CanQualType ClassTy
|
||||
= Context.getCanonicalType(Context.getTagDeclType(getParent()));
|
||||
|
|
|
@ -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<CXXConstructorDecl>(*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<CXXConstructorDecl>(*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<FunctionTemplateDecl>(*Con);
|
||||
if (ConstructorTmpl->isInvalidDecl())
|
||||
continue;
|
||||
|
||||
Constructor = cast<CXXConstructorDecl>(
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<typename T> 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<X6> tf;
|
||||
X5<X6> tf2(tf);
|
||||
}
|
||||
|
||||
namespace PR8182 {
|
||||
struct foo {
|
||||
foo();
|
||||
template<class T> foo(T&);
|
||||
|
||||
private:
|
||||
foo(const foo&);
|
||||
};
|
||||
|
||||
void test_foo() {
|
||||
foo f1;
|
||||
foo f2(f1);
|
||||
foo f3 = f1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue