https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/102581
>From 9d5d8d99db6f7fa0b6973fe55582de9d34740b19 Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <zw...@outlook.com> Date: Fri, 9 Aug 2024 15:45:40 +0800 Subject: [PATCH 1/2] Support non-reference structured bindings with braced array as initializer --- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Sema/Initialization.h | 4 ++ clang/lib/Sema/SemaInit.cpp | 82 +++++++++++++++++----- clang/test/SemaCXX/cxx1z-decomposition.cpp | 31 +++++++- 4 files changed, 99 insertions(+), 20 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7beef7be0e6a53..4e725ce4770e99 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -211,6 +211,8 @@ Bug Fixes to C++ Support - Clang now preserves the unexpanded flag in a lambda transform used for pack expansion. (#GH56852), (#GH85667), (#GH99877). - Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions. +- Clang now correctly handle non-reference structured bindings with braced + array as initializer. (#GH31813) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index 4b876db436b48c..dfe3d5ff0a252c 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -1384,6 +1384,10 @@ class InitializationSequence { void AddParenthesizedListInitStep(QualType T); + /// Only used when initializing non-reference structured bindings from braced + /// array. Unwrap the initializer list to get the array for array copy. + void AddUnwrapInitListAtFirst(InitListExpr *Syntactic); + /// Add steps to unwrap a initializer list for a reference around a /// single element and rewrap it at the end. void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 2666e60c0dd67c..5884955838006e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4091,6 +4091,15 @@ void InitializationSequence::AddParenthesizedListInitStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddUnwrapInitListAtFirst(InitListExpr *Syntactic) { + assert(Syntactic->getNumInits() == 1 && + "Can only unwrap trivial init lists."); + Step S; + S.Kind = SK_UnwrapInitList; + S.Type = Syntactic->getInit(0)->getType(); + Steps.insert(Steps.begin(), S); +} + void InitializationSequence::RewrapReferenceInitList(QualType T, InitListExpr *Syntactic) { assert(Syntactic->getNumInits() == 1 && @@ -4167,6 +4176,33 @@ static void MaybeProduceObjCObject(Sema &S, } } +/// Initialize an array from another array +static void TryArrayCopy(Sema &S, const InitializationKind &Kind, + const InitializedEntity &Entity, Expr *Initializer, + QualType DestType, InitializationSequence &Sequence, + bool TreatUnavailableAsInvalid) { + // If source is a prvalue, use it directly. + if (Initializer->isPRValue()) { + Sequence.AddArrayInitStep(DestType, /*IsGNUExtension*/ false); + return; + } + + // Emit element-at-a-time copy loop. + InitializedEntity Element = + InitializedEntity::InitializeElement(S.Context, 0, Entity); + QualType InitEltT = + S.Context.getAsArrayType(Initializer->getType())->getElementType(); + OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT, + Initializer->getValueKind(), + Initializer->getObjectKind()); + Expr *OVEAsExpr = &OVE; + Sequence.InitializeFrom(S, Element, Kind, OVEAsExpr, + /*TopLevelOfInitList*/ false, + TreatUnavailableAsInvalid); + if (Sequence) + Sequence.AddArrayInitLoopStep(Entity.getType(), InitEltT); +} + static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4775,6 +4811,31 @@ static void TryListInitialization(Sema &S, } if (const ArrayType *DestAT = S.Context.getAsArrayType(DestType)) { Expr *SubInit[1] = {InitList->getInit(0)}; + + // C++17 [dcl.struct.bind]p1: + // ... If the assignment-expression in the initializer has array type A + // and no ref-qualifier is present, e has type cv A and each element is + // copy-initialized or direct-initialized from the corresponding element + // of the assignment-expression as specified by the form of the + // initializer. + // + // This is a special case not following list-initialization. + if (isa<ConstantArrayType>(DestAT) && + Entity.getKind() == InitializedEntity::EK_Variable && + isa<DecompositionDecl>(Entity.getDecl())) { + assert( + S.Context.hasSameUnqualifiedType(SubInit[0]->getType(), DestType) && + "Deduced to other type?"); + TryArrayCopy(S, + InitializationKind::CreateCopy(Kind.getLocation(), + InitList->getLBraceLoc()), + Entity, SubInit[0], DestType, Sequence, + TreatUnavailableAsInvalid); + if (Sequence) + Sequence.AddUnwrapInitListAtFirst(InitList); + return; + } + if (!isa<VariableArrayType>(DestAT) && IsStringInit(SubInit[0], DestAT, S.Context) == SIF_None) { InitializationKind SubKind = @@ -6460,25 +6521,8 @@ void InitializationSequence::InitializeFrom(Sema &S, S.Context.hasSameUnqualifiedType(Initializer->getType(), Entity.getType()) && canPerformArrayCopy(Entity)) { - // If source is a prvalue, use it directly. - if (Initializer->isPRValue()) { - AddArrayInitStep(DestType, /*IsGNUExtension*/false); - return; - } - - // Emit element-at-a-time copy loop. - InitializedEntity Element = - InitializedEntity::InitializeElement(S.Context, 0, Entity); - QualType InitEltT = - Context.getAsArrayType(Initializer->getType())->getElementType(); - OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT, - Initializer->getValueKind(), - Initializer->getObjectKind()); - Expr *OVEAsExpr = &OVE; - InitializeFrom(S, Element, Kind, OVEAsExpr, TopLevelOfInitList, - TreatUnavailableAsInvalid); - if (!Failed()) - AddArrayInitLoopStep(Entity.getType(), InitEltT); + TryArrayCopy(S, Kind, Entity, Initializer, DestType, *this, + TreatUnavailableAsInvalid); return; } diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 19c730303625ee..f05a962a3b3d21 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -198,4 +198,33 @@ namespace lambdas { } } -// FIXME: by-value array copies +namespace by_value_array_copy { + struct explicit_copy { + explicit_copy() = default; // expected-note 2{{candidate constructor not viable: requires 0 arguments, but 1 was provided}} + explicit explicit_copy(const explicit_copy&) = default; // expected-note 2{{explicit constructor is not a candidate}} + }; + + constexpr int direct_initialization_for_elements() { + int arr[3]{1, 2, 3}; + auto [a1, b1, c1](arr); + explicit_copy ec_arr[2]; + auto [a2, b2](ec_arr); + arr[0]--; + return a1 + b1 + c1 + arr[0]; + } + static_assert(direct_initialization_for_elements() == 6); + + void copy_initialization_for_elements() { + int arr[2]{1, 2}; + auto [a1, b1] = arr; + auto [a2, b2]{arr}; // GH31813 + explicit_copy ec_arr[2]; + auto [a3, b3] = ec_arr; // expected-error {{no matching constructor for initialization of 'explicit_copy[2]'}} + auto [a4, b4]{ec_arr}; // expected-error {{no matching constructor for initialization of 'explicit_copy[2]'}} + + // Test prvalue + using T = explicit_copy[2]; + auto [a5, b5] = T{}; + auto [a6, b6]{T{}}; + } +} // namespace by_value_array_copy >From ad648f0744f8622d27ad03b15db34c1c0a94e67f Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <zw...@outlook.com> Date: Sat, 24 Aug 2024 08:44:46 +0800 Subject: [PATCH 2/2] Modify comment, release note and name of function --- clang/docs/ReleaseNotes.rst | 4 ++-- clang/include/clang/Sema/Initialization.h | 7 ++++--- clang/lib/Sema/SemaInit.cpp | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4e725ce4770e99..e46833716add4f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -211,8 +211,8 @@ Bug Fixes to C++ Support - Clang now preserves the unexpanded flag in a lambda transform used for pack expansion. (#GH56852), (#GH85667), (#GH99877). - Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions. -- Clang now correctly handle non-reference structured bindings with braced - array as initializer. (#GH31813) +- Clang now correctly handle initializing array-typed structured bindings with + direct-list-initialization. (#GH31813) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index dfe3d5ff0a252c..1affb19f360c00 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -1384,9 +1384,10 @@ class InitializationSequence { void AddParenthesizedListInitStep(QualType T); - /// Only used when initializing non-reference structured bindings from braced - /// array. Unwrap the initializer list to get the array for array copy. - void AddUnwrapInitListAtFirst(InitListExpr *Syntactic); + /// Only used when initializing array-typed structured bindings with + /// direct-list-initialization. Unwrap the initializer list to get the array + /// for array copy. + void AddUnwrapInitListAtTheBeginning(InitListExpr *Syntactic); /// Add steps to unwrap a initializer list for a reference around a /// single element and rewrap it at the end. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5884955838006e..a3d4a6329d0f40 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -4817,7 +4817,7 @@ static void TryListInitialization(Sema &S, // and no ref-qualifier is present, e has type cv A and each element is // copy-initialized or direct-initialized from the corresponding element // of the assignment-expression as specified by the form of the - // initializer. + // initializer. ... // // This is a special case not following list-initialization. if (isa<ConstantArrayType>(DestAT) && @@ -4832,7 +4832,7 @@ static void TryListInitialization(Sema &S, Entity, SubInit[0], DestType, Sequence, TreatUnavailableAsInvalid); if (Sequence) - Sequence.AddUnwrapInitListAtFirst(InitList); + Sequence.AddUnwrapInitListAtTheBeginning(InitList); return; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits