When we are performing copy initialization of a class type via its
copy constructor, suppress user-defined conversions on the argument. Otherwise, we can end up in a recursion loop where the bind the argument of the copy constructor to another copy constructor call, whose argument is then a copy constructor call... Found by Boost.Regex which, alas, still isn't building. llvm-svn: 102269
This commit is contained in:
parent
cfc12ddb0a
commit
c779e99540
|
@ -2636,25 +2636,36 @@ static void TryConstructorInitialization(Sema &S,
|
|||
Con != ConEnd; ++Con) {
|
||||
NamedDecl *D = *Con;
|
||||
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
|
||||
|
||||
bool SuppressUserConversions = false;
|
||||
|
||||
// Find the constructor (which may be a template).
|
||||
CXXConstructorDecl *Constructor = 0;
|
||||
FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
|
||||
if (ConstructorTmpl)
|
||||
Constructor = cast<CXXConstructorDecl>(
|
||||
ConstructorTmpl->getTemplatedDecl());
|
||||
else
|
||||
else {
|
||||
Constructor = cast<CXXConstructorDecl>(D);
|
||||
|
||||
// If we're performing copy initialization using a copy constructor, we
|
||||
// suppress user-defined conversions on the arguments.
|
||||
// FIXME: Move constructors?
|
||||
if (Kind.getKind() == InitializationKind::IK_Copy &&
|
||||
Constructor->isCopyConstructor())
|
||||
SuppressUserConversions = true;
|
||||
}
|
||||
|
||||
if (!Constructor->isInvalidDecl() &&
|
||||
(AllowExplicit || !Constructor->isExplicit())) {
|
||||
if (ConstructorTmpl)
|
||||
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
|
||||
/*ExplicitArgs*/ 0,
|
||||
Args, NumArgs, CandidateSet);
|
||||
Args, NumArgs, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
else
|
||||
S.AddOverloadCandidate(Constructor, FoundDecl,
|
||||
Args, NumArgs, CandidateSet);
|
||||
Args, NumArgs, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2803,7 +2814,8 @@ static void TryUserDefinedConversion(Sema &S,
|
|||
Con != ConEnd; ++Con) {
|
||||
NamedDecl *D = *Con;
|
||||
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
|
||||
|
||||
bool SuppressUserConversions = false;
|
||||
|
||||
// Find the constructor (which may be a template).
|
||||
CXXConstructorDecl *Constructor = 0;
|
||||
FunctionTemplateDecl *ConstructorTmpl
|
||||
|
@ -2811,18 +2823,29 @@ static void TryUserDefinedConversion(Sema &S,
|
|||
if (ConstructorTmpl)
|
||||
Constructor = cast<CXXConstructorDecl>(
|
||||
ConstructorTmpl->getTemplatedDecl());
|
||||
else
|
||||
else {
|
||||
Constructor = cast<CXXConstructorDecl>(D);
|
||||
|
||||
// If we're performing copy initialization using a copy constructor, we
|
||||
// suppress user-defined conversions on the arguments.
|
||||
// FIXME: Move constructors?
|
||||
if (Kind.getKind() == InitializationKind::IK_Copy &&
|
||||
Constructor->isCopyConstructor())
|
||||
SuppressUserConversions = true;
|
||||
|
||||
}
|
||||
|
||||
if (!Constructor->isInvalidDecl() &&
|
||||
Constructor->isConvertingConstructor(AllowExplicit)) {
|
||||
if (ConstructorTmpl)
|
||||
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
|
||||
/*ExplicitArgs*/ 0,
|
||||
&Initializer, 1, CandidateSet);
|
||||
&Initializer, 1, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
else
|
||||
S.AddOverloadCandidate(Constructor, FoundDecl,
|
||||
&Initializer, 1, CandidateSet);
|
||||
&Initializer, 1, CandidateSet,
|
||||
SuppressUserConversions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
struct ToBool { explicit operator bool(); };
|
||||
|
||||
struct B;
|
||||
struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}} \
|
||||
// expected-note 2 {{candidate is the implicit copy constructor}}
|
||||
struct A { A(); A(const B&); }; // expected-note 2 {{candidate constructor}}
|
||||
struct B { operator A() const; }; // expected-note 2 {{candidate function}}
|
||||
struct I { operator int(); };
|
||||
struct J { operator I(); };
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
// This used to crash Clang.
|
||||
struct Flip;
|
||||
struct Flop { // expected-note{{candidate is the implicit copy constructor}}
|
||||
struct Flop {
|
||||
Flop();
|
||||
Flop(const Flip&); // expected-note{{candidate constructor}}
|
||||
};
|
||||
|
@ -202,3 +202,16 @@ namespace smart_ptr {
|
|||
return X(Y());
|
||||
}
|
||||
}
|
||||
|
||||
struct Any {
|
||||
Any(...);
|
||||
};
|
||||
|
||||
struct Other {
|
||||
Other(const Other &);
|
||||
Other();
|
||||
};
|
||||
|
||||
void test_any() {
|
||||
Any any = Other(); // expected-error{{cannot pass object of non-POD type 'Other' through variadic constructor; call will abort at runtime}}
|
||||
}
|
||||
|
|
|
@ -408,7 +408,7 @@ namespace PR6483 {
|
|||
}
|
||||
|
||||
namespace PR6078 {
|
||||
struct A { // expected-note{{candidate is the implicit copy constructor}}
|
||||
struct A {
|
||||
A(short); // expected-note{{candidate constructor}}
|
||||
A(long); // expected-note{{candidate constructor}}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue