diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4232,6 +4232,14 @@ return; } + bool CopyElisionPossible = false; + auto ElideConstructor = [&] { + // Convert qualifications if necessary. + Sequence.AddQualificationConversionStep(DestType, VK_PRValue); + if (ILE) + Sequence.RewrapReferenceInitList(DestType, ILE); + }; + // C++17 [dcl.init]p17: // - If the initializer expression is a prvalue and the cv-unqualified // version of the source type is the same class as the class of the @@ -4246,13 +4254,17 @@ Entity.getKind() != InitializedEntity::EK_Delegating && Entity.getKind() != InitializedEntity::EK_LambdaToBlockConversionBlockElement && - Args.size() == 1 && Args[0]->isPRValue() && - S.Context.hasSameUnqualifiedType(Args[0]->getType(), DestType)) { - // Convert qualifications if necessary. - Sequence.AddQualificationConversionStep(DestType, VK_PRValue); - if (ILE) - Sequence.RewrapReferenceInitList(DestType, ILE); - return; + UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isPRValue() && + S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { + if (ILE && !DestType->isAggregateType()) { + // CWG2311: T{ prvalue_of_type_T } is not eligible for copy elision + // Make this an elision if this won't call an initializer-list constructor + // (Always on an aggregate type or check constructors first) + CopyElisionPossible = true; + } else { + ElideConstructor(); + return; + } } const RecordType *DestRecordType = DestType->getAs(); @@ -4314,6 +4326,14 @@ IsListInit); } if (Result) { + // Ambiguity means an initializer list constructor would not be called + // Or a deleted non-initializer-list constructor was to be called + if (CopyElisionPossible && + (Result != OR_Deleted || !S.isInitListConstructor(Best->Function))) { + ElideConstructor(); + return; + } + Sequence.SetOverloadFailure( IsListInit ? InitializationSequence::FK_ListConstructorOverloadFailed : InitializationSequence::FK_ConstructorOverloadFailed, @@ -4332,6 +4352,8 @@ QualType ConvType = CD->getConversionType(); assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) && "should not have selected this conversion function"); + assert(!CopyElisionPossible && + "conversion function picked converting to the same type?"); Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType, HadMultipleCandidates); if (!S.Context.hasSameType(ConvType, DestType)) @@ -4342,6 +4364,10 @@ } CXXConstructorDecl *CtorDecl = cast(Best->Function); + if (CopyElisionPossible && !S.isInitListConstructor(CtorDecl)) { + ElideConstructor(); + return; + } if (Result != OR_Deleted) { // C++11 [dcl.init]p6: // If a program calls for the default initialization of an object diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp --- a/clang/test/CXX/drs/dr23xx.cpp +++ b/clang/test/CXX/drs/dr23xx.cpp @@ -5,6 +5,16 @@ // RUN: %clang_cc1 -std=c++20 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s // RUN: %clang_cc1 -std=c++23 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s +namespace std { + __extension__ typedef __SIZE_TYPE__ size_t; + + template struct initializer_list { + const E *p; size_t n; + initializer_list(const E *p, size_t n); + initializer_list(); + }; +} + #if __cplusplus >= 201103L namespace dr2303 { // dr2303: 12 template @@ -37,6 +47,38 @@ } //namespace dr2303 #endif +namespace dr2311 { +#if __cplusplus >= 201707L +template +void test() { + // These should all be elided (no move) + T a = T{T(0)}; + T b{T(0)}; + auto c{T(0)}; + T d = {T(0)}; + auto e = {T(0)}; +#if __cplusplus >= 202302L + auto f = auto{T(0)}; +#endif +} + +struct NonMovable { + NonMovable(int); + NonMovable(NonMovable&&) = delete; +}; + +template void test(); + +struct NonMovableNonApplicableIList { + NonMovableNonApplicableIList(int); + NonMovableNonApplicableIList(NonMovableNonApplicableIList&&) = delete; + NonMovableNonApplicableIList(std::initializer_list); +}; + +template void test(); +#endif +} + // dr2331: na #if __cplusplus >= 201103L