From: Douglas Gregor Date: Sat, 10 Mar 2012 06:53:13 +0000 (+0000) Subject: Only make a call to a copy constructor elidable if in fact we are X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f52757d63f90e0d03eba20318f6036db944ba50c;p=clang Only make a call to a copy constructor elidable if in fact we are doing a copy. Fixes PR12139. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152485 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 21a394f715..e84f66b963 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -8876,6 +8876,25 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( } } +/// \brief Determine whether the given list arguments contains exactly one +/// "real" (non-default) argument. +static bool hasOneRealArgument(MultiExprArg Args) { + switch (Args.size()) { + case 0: + return false; + + default: + if (!Args.get()[1]->isDefaultArgument()) + return false; + + // fall through + case 1: + return !Args.get()[0]->isDefaultArgument(); + } + + return false; +} + ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, @@ -8897,7 +8916,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_Complete && - Constructor->isCopyOrMoveConstructor() && ExprArgs.size() >= 1) { + Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { Expr *SubExpr = ((Expr **)ExprArgs.get())[0]; Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent()); } diff --git a/test/CodeGenCXX/copy-constructor-elim-2.cpp b/test/CodeGenCXX/copy-constructor-elim-2.cpp index a4a688f737..9480cbfdbb 100644 --- a/test/CodeGenCXX/copy-constructor-elim-2.cpp +++ b/test/CodeGenCXX/copy-constructor-elim-2.cpp @@ -53,3 +53,25 @@ void f() { } } + +namespace PR12139 { + struct A { + A() : value(1) { } + A(A const &, int value = 2) : value(value) { } + int value; + + static A makeA() { A a; a.value = 2; return a; } + }; + + // CHECK: define i32 @_ZN7PR121394testEv + int test() { + // CHECK: call void @_ZN7PR121391A5makeAEv + // CHECK-NEXT: call void @_ZN7PR121391AC1ERKS0_i + A a(A::makeA(), 3); + // CHECK-NEXT: getelementptr inbounds + // CHECK-NEXT: load + // CHECK-NEXT: ret i32 + return a.value; + } +} +