Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -266,6 +266,11 @@ /// if Sema is already doing so, which would cause infinite recursions. bool IsBuildingRecoveryCallExpr; + /// \brief All constructors in construction. This is to detect if + /// converting the arguments calls any constructor being constructed, + /// which leads to an infinite recursion. + llvm::SmallVector CtorsInConstruction; + /// ExprNeedsCleanups - True if the current evaluation context /// requires cleanups to be run at its conclusion. bool ExprNeedsCleanups; Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -10147,6 +10147,13 @@ else ConvertedArgs.reserve(NumArgs); + // Mark this constructor being constructed so that its argument construction + // should not call itself. + CXXConstructorDecl *Ctor = Constructor; + if (FunctionTemplateDecl *FuncTmpl = Ctor->getPrimaryTemplate()) + Ctor = cast(FuncTmpl->getTemplatedDecl()); + CtorsInConstruction.push_back(Ctor); + VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; SmallVector AllArgs; @@ -10165,6 +10172,9 @@ AllArgs.size()), Proto, Loc); + // Cleanup once finished the constructor call. + CtorsInConstruction.pop_back(); + return Invalid; } Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -3008,7 +3008,15 @@ SuppressUserConversions = true; } - if (!Constructor->isInvalidDecl() && + // If Sema is already building this constructor call, then this constructor + // cannot be a candidate for initializing its arguments. Otherwise, this + // leads to an infinite recursion. + bool InConstruction = + S.CtorsInConstruction.end() != std::find(S.CtorsInConstruction.begin(), + S.CtorsInConstruction.end(), + Constructor); + + if (!Constructor->isInvalidDecl() && !InConstruction && (AllowExplicit || !Constructor->isExplicit()) && (!OnlyListConstructors || S.isInitListConstructor(Constructor))) { if (ConstructorTmpl) Index: test/SemaCXX/constructor.cpp =================================================================== --- test/SemaCXX/constructor.cpp +++ test/SemaCXX/constructor.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s typedef int INT; class Foo { @@ -85,3 +85,34 @@ A::S::~S() {} +namespace PR16239 { +struct Foo; +struct Bar; + +struct Move2 { + Move2(Foo f); // expected-note {{passing argument to parameter 'f' here}} + Move2(Bar b); // expected-note {{passing argument to parameter 'b' here}} +}; + +struct Foo { + Foo(const Move2&); + + Foo(Foo&); // expected-note {{candidate constructor not viable}} +}; + +struct Bar { + template + Bar(const Move2&, T t = T()); + + Bar(Bar&); // expected-note {{candidate constructor not viable}} +}; + +Foo func_foo(); +Bar func_bar(); + +void Baz() { + Foo f = func_foo(); // expected-error{{no matching constructor for initialization}} + Bar b = func_bar(); // expected-error{{no matching constructor for initialization}} +} + +} // namespace