Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -870,6 +870,10 @@ Expr *SourceExpr; SourceLocation Loc; + /// This OVE is unique semantic reference to its source expressio if this bit + /// is set to true. + bool IsUnique = false; + public: OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, ExprObjectKind OK = OK_Ordinary, @@ -925,6 +929,9 @@ /// place. Expr *getSourceExpr() const { return SourceExpr; } + void setIsUnique() { IsUnique = true; } + bool isUnique() const { return IsUnique; } + static bool classof(const Stmt *T) { return T->getStmtClass() == OpaqueValueExprClass; } Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -4170,6 +4170,18 @@ return getOpaqueLValueMapping(e); } +LValue CodeGenFunction::getOpaqueLValueMapping(const OpaqueValueExpr *e) { + assert(OpaqueValueMapping::shouldBindAsLValue(e)); + + if (e->isUnique()) + return EmitLValue(e->getSourceExpr()); + + llvm::DenseMap::iterator + it = OpaqueLValues.find(e); + assert(it != OpaqueLValues.end() && "no mapping for opaque value!"); + return it->second; +} + RValue CodeGenFunction::EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc) { @@ -4719,6 +4731,8 @@ // If this semantic expression is an opaque value, bind it // to the result of its source expression. if (const auto *ov = dyn_cast(semantic)) { + if (ov->isUnique()) + continue; // If this is the result expression, we may need to evaluate // directly into the slot. Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -606,7 +606,11 @@ } void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) { - EmitFinalDestCopy(e->getType(), CGF.getOpaqueLValueMapping(e)); + // Avoid copying if OVE is a unique reference to its source expression. + if (e->isUnique()) + Visit(e->getSourceExpr()); + else + EmitFinalDestCopy(e->getType(), CGF.getOpaqueLValueMapping(e)); } void Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -2124,14 +2124,7 @@ /// getOpaqueLValueMapping - Given an opaque value expression (which /// must be mapped to an l-value), return its mapping. - const LValue &getOpaqueLValueMapping(const OpaqueValueExpr *e) { - assert(OpaqueValueMapping::shouldBindAsLValue(e)); - - llvm::DenseMap::iterator - it = OpaqueLValues.find(e); - assert(it != OpaqueLValues.end() && "no mapping for opaque value!"); - return it->second; - } + LValue getOpaqueLValueMapping(const OpaqueValueExpr *e); /// getOpaqueRValueMapping - Given an opaque value expression (which /// must be mapped to an r-value), return its mapping. Index: lib/Sema/SemaPseudoObject.cpp =================================================================== --- lib/Sema/SemaPseudoObject.cpp +++ lib/Sema/SemaPseudoObject.cpp @@ -428,6 +428,9 @@ Expr *syntacticLHS = rebuildAndCaptureObject(LHS); OpaqueValueExpr *capturedRHS = capture(RHS); + if (capturedRHS->getType()->getAsCXXRecordDecl() && capturedRHS->isRValue()) + capturedRHS->setIsUnique(); + // In some very specific cases, semantic analysis of the RHS as an // expression may require it to be rewritten. In these cases, we // cannot safely keep the OVE around. Fortunately, we don't really Index: test/CodeGenObjCXX/property-dot-copy-elision.mm =================================================================== --- /dev/null +++ test/CodeGenObjCXX/property-dot-copy-elision.mm @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++1z -fobjc-arc -o - %s | FileCheck %s + +struct S0 { + id f; +}; + +struct S1 { + S1(); + S1(S0); + id f; +}; + +@interface C +@property S1 f; +@end +@implementation C +@end + +// CHECK-LABEL: define void @_Z5test0P1C( +// CHECK: %{{.*}} = alloca % +// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_S1:.*]], align +// CHECK: %[[AGG_TMP_1:.*]] = alloca %[[STRUCT_S0:.*]], align +// CHECK: call void @_ZN2S0C1Ev(%[[STRUCT_S0]]* %[[AGG_TMP_1]]) +// CHECK: call void @_ZN2S1C1E2S0(%[[STRUCT_S1]]* %[[AGG_TMP]], %[[STRUCT_S0]]* %[[AGG_TMP_1]]) +// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %[[STRUCT_S1]]*)*)(i8* %{{.*}}, i8* %{{.*}}, %[[STRUCT_S1]]* %[[AGG_TMP]]) + +void test0(C *c) { + c.f = S0(); +} + +// CHECK: define void @_Z5test1P1C( +// CHECK: %{{.*}} = alloca % +// CHECK: %[[TEMP_LVALUE:.*]] = alloca %[[STRUCT_S1:.*]], align +// CHECK: call void @_ZN2S1C1Ev(%[[STRUCT_S1]]* %[[TEMP_LVALUE]]) +// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %[[STRUCT_S1]]*)*)(i8* %{{.*}}, i8* %{{.*}}, %[[STRUCT_S1]]* %[[TEMP_LVALUE]]) + +void test1(C *c) { + c.f = S1(); +} Index: test/CodeGenObjCXX/property-objects.mm =================================================================== --- test/CodeGenObjCXX/property-objects.mm +++ test/CodeGenObjCXX/property-objects.mm @@ -72,7 +72,7 @@ // rdar://8379892 // CHECK-LABEL: define void @_Z1fP1A -// CHECK: call void @_ZN1XC1Ev(%struct.X* [[LVTEMP:%[a-zA-Z0-9\.]+]]) +// CHECK: call void @_ZN1XC1Ev(%struct.X* [[LVTEMP:%.+]]) // CHECK: call void @_ZN1XC1ERKS_(%struct.X* [[AGGTMP:%[a-zA-Z0-9\.]+]], %struct.X* dereferenceable({{[0-9]+}}) [[LVTEMP]]) // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %struct.X*)*)({{.*}} %struct.X* [[AGGTMP]]) struct X {