Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -60,6 +60,9 @@ EK_New, /// \brief The entity being initialized is a temporary object. EK_Temporary, + // \brief The entity being initialized is first operand in the GNU "x ?: y" + // extension. + EK_GNUConditionalOperatorLHSElement, /// \brief The entity being initialized is a base member subobject. EK_Base, /// \brief The initialization is being done by a delegating constructor. @@ -298,7 +301,13 @@ Result.TypeInfo = TypeInfo; return Result; } - + + static InitializedEntity + InitializeGNUConditionalOperatorLHSElement(QualType Type) { + return InitializedEntity(EK_GNUConditionalOperatorLHSElement, + SourceLocation(), Type); + } + /// \brief Create the initialization entity for a related result. static InitializedEntity InitializeRelatedResult(ObjCMethodDecl *MD, QualType Type) { Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -5631,17 +5631,24 @@ if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. - InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); + // C++17: In case of the gnu "x ?: y" extension, ensure we avoid eliding + // the LHS temporary. + ExprResult LHSCopy = + isa(LHS.get()) + ? PerformCopyInitialization( + InitializedEntity:: + InitializeGNUConditionalOperatorLHSElement(LTy), + SourceLocation(), LHS) + : PerformCopyInitialization( + InitializedEntity::InitializeTemporary(LTy), + SourceLocation(), LHS); - ExprResult LHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - LHS); if (LHSCopy.isInvalid()) return QualType(); - ExprResult RHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - RHS); + ExprResult RHSCopy = PerformCopyInitialization( + InitializedEntity::InitializeTemporary(LTy), SourceLocation(), RHS); + if (RHSCopy.isInvalid()) return QualType(); Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -968,6 +968,7 @@ case InitializedEntity::EK_New: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_CompoundLiteralInit: // No warning, braces are part of the syntax of the underlying construct. break; @@ -2958,11 +2959,12 @@ case EK_LambdaCapture: return DeclarationName(Capture.VarID); - + case EK_Result: case EK_Exception: case EK_New: case EK_Temporary: + case EK_GNUConditionalOperatorLHSElement: case EK_Base: case EK_Delegating: case EK_ArrayElement: @@ -2993,6 +2995,7 @@ case EK_Exception: case EK_New: case EK_Temporary: + case EK_GNUConditionalOperatorLHSElement: case EK_Base: case EK_Delegating: case EK_ArrayElement: @@ -3022,6 +3025,7 @@ case EK_Binding: case EK_New: case EK_Temporary: + case EK_GNUConditionalOperatorLHSElement: case EK_CompoundLiteralInit: case EK_Base: case EK_Delegating: @@ -3055,6 +3059,9 @@ case EK_Binding: OS << "Binding"; break; case EK_New: OS << "New"; break; case EK_Temporary: OS << "Temporary"; break; + case EK_GNUConditionalOperatorLHSElement: + OS << "ConditionalOperatorLHSElement"; + break; case EK_CompoundLiteralInit: OS << "CompoundLiteral";break; case EK_RelatedResult: OS << "RelatedResult"; break; case EK_Base: OS << "Base"; break; @@ -3710,11 +3717,14 @@ // class or delegating to another constructor from a mem-initializer. // ObjC++: Lambda captured by the block in the lambda to block conversion // should avoid copy elision. + // GNU "x ?: y" extension: avoid eliding the LHS temporary. if (S.getLangOpts().CPlusPlus1z && Entity.getKind() != InitializedEntity::EK_Base && Entity.getKind() != InitializedEntity::EK_Delegating && Entity.getKind() != InitializedEntity::EK_LambdaToBlockConversionBlockElement && + Entity.getKind() != + InitializedEntity::EK_GNUConditionalOperatorLHSElement && UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() && S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { // Convert qualifications if necessary. @@ -5578,13 +5588,14 @@ if (Entity.getDecl() && isa(Entity.getDecl()->getDeclContext())) return Sema::AA_Sending; - + return !Diagnose ? Sema::AA_Passing : Sema::AA_Passing_CFAudited; - + case InitializedEntity::EK_Result: return Sema::AA_Returning; case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_RelatedResult: // FIXME: Can we tell apart casting vs. converting? return Sema::AA_Casting; @@ -5627,6 +5638,7 @@ case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_RelatedResult: case InitializedEntity::EK_Binding: return true; @@ -5656,6 +5668,7 @@ case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_CompoundLiteralInit: @@ -5682,12 +5695,13 @@ case InitializedEntity::EK_LambdaCapture: return Entity.getCaptureLoc(); - + case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_Member: case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: @@ -5950,6 +5964,7 @@ unsigned NumArgs) { switch (Entity.getKind()) { case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_CompoundLiteralInit: case InitializedEntity::EK_RelatedResult: break; @@ -6141,6 +6156,7 @@ case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_LambdaCapture: case InitializedEntity::EK_CompoundLiteralInit: case InitializedEntity::EK_RelatedResult: @@ -6195,6 +6211,7 @@ return nullptr; case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_GNUConditionalOperatorLHSElement: case InitializedEntity::EK_CompoundLiteralInit: case InitializedEntity::EK_RelatedResult: // We don't yet know the storage duration of the surrounding temporary. Index: test/CodeGenCXX/gnu-conditional-extension.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/gnu-conditional-extension.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++1z -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s + +struct Copyable { + Copyable(); + Copyable(const Copyable &x); + operator bool(); +}; + +Copyable makeCopyable() { return Copyable(); } + +Copyable avoidElidingCopy() { + Copyable C = makeCopyable() ?: Copyable(); + return C; +} + +struct NonCopyable { + NonCopyable(); + NonCopyable(const NonCopyable &x) = delete; + NonCopyable(NonCopyable &&x); + operator bool(); +}; + +NonCopyable makeNonCopyable() { return NonCopyable(); } + +NonCopyable avoidElidingMove() { + NonCopyable N = makeNonCopyable() ?: NonCopyable(); + return N; +} + +// CHECK-LABEL: define void @_Z16avoidElidingCopyv(%struct.Copyable* noalias sret %agg.result) +// CHECK: call void @_ZN8CopyableC1ERKS_(%struct.Copyable* %agg.result, %struct.Copyable* dereferenceable(1) %tmp) +// CHECK-LABEL: define void @_Z16avoidElidingMovev(%struct.NonCopyable* noalias sret %agg.result) +// CHECK: call void @_ZN11NonCopyableC1EOS_(%struct.NonCopyable* %agg.result, %struct.NonCopyable* dereferenceable(1) %tmp)