From c779e995402ac3e6dc10655482b5e0be34dfa23f Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 24 Apr 2010 20:54:38 +0000 Subject: [PATCH] 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 --- clang/lib/Sema/SemaInit.cpp | 39 +++++++++++++++++----- clang/test/SemaCXX/conditional-expr.cpp | 3 +- clang/test/SemaCXX/conversion-function.cpp | 15 ++++++++- clang/test/SemaCXX/overload-call.cpp | 2 +- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5c55b56c7d39..d552b163994c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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(D); if (ConstructorTmpl) Constructor = cast( ConstructorTmpl->getTemplatedDecl()); - else + else { Constructor = cast(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( ConstructorTmpl->getTemplatedDecl()); - else + else { Constructor = cast(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); } } } diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index aa4132323919..a812a5920d65 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -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(); }; diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index dfc065064190..3e96d02495fe 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -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}} +} diff --git a/clang/test/SemaCXX/overload-call.cpp b/clang/test/SemaCXX/overload-call.cpp index feec9df6b7a5..79c74cec4947 100644 --- a/clang/test/SemaCXX/overload-call.cpp +++ b/clang/test/SemaCXX/overload-call.cpp @@ -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}} };