https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/94889
>From 217c00f47aaa65b113d1c1cfd93a9c4e1d235c1a Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sun, 9 Jun 2024 11:49:18 +0800 Subject: [PATCH 1/2] [Clang] Fix two issues of CTAD for aggregates --- clang/lib/Sema/SemaInit.cpp | 56 +++++++++++++++------ clang/test/SemaTemplate/deduction-guide.cpp | 19 +++++++ 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 79bdc8e9f8783..de2ea639bbba8 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -313,6 +313,8 @@ class InitListChecker { InitListExpr *FullyStructuredList = nullptr; NoInitExpr *DummyExpr = nullptr; SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr; + SmallVectorImpl<QualType> + *AggrDeductionCandidateParamTypesWithoutBraceElision = nullptr; NoInitExpr *getDummyInit() { if (!DummyExpr) @@ -506,14 +508,19 @@ class InitListChecker { Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution = false, - SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr); + SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr, + SmallVectorImpl<QualType> + *AggrDeductionCandidateParamTypesWithoutBraceElision = nullptr); InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, - SmallVectorImpl<QualType> &AggrDeductionCandidateParamTypes) + SmallVectorImpl<QualType> &AggrDeductionCandidateParamTypes, + SmallVectorImpl<QualType> + &AggrDeductionCandidateParamTypesWithoutBraceElision) : InitListChecker(S, Entity, IL, T, /*VerifyOnly=*/true, /*TreatUnavailableAsInvalid=*/false, /*InOverloadResolution=*/false, - &AggrDeductionCandidateParamTypes){}; + &AggrDeductionCandidateParamTypes, + &AggrDeductionCandidateParamTypesWithoutBraceElision) {} bool HadError() { return hadError; } @@ -982,11 +989,15 @@ static bool hasAnyDesignatedInits(const InitListExpr *IL) { InitListChecker::InitListChecker( Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution, - SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes) + SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes, + SmallVectorImpl<QualType> + *AggrDeductionCandidateParamTypesWithoutBraceElision) : SemaRef(S), VerifyOnly(VerifyOnly), TreatUnavailableAsInvalid(TreatUnavailableAsInvalid), InOverloadResolution(InOverloadResolution), - AggrDeductionCandidateParamTypes(AggrDeductionCandidateParamTypes) { + AggrDeductionCandidateParamTypes(AggrDeductionCandidateParamTypes), + AggrDeductionCandidateParamTypesWithoutBraceElision( + AggrDeductionCandidateParamTypesWithoutBraceElision) { if (!VerifyOnly || hasAnyDesignatedInits(IL)) { FullyStructuredList = createInitListExpr(T, IL->getSourceRange(), IL->getNumInits()); @@ -1448,13 +1459,17 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // brace elision is not considered for any aggregate element that has a // dependent non-array type or an array type with a value-dependent // bound - assert(AggrDeductionCandidateParamTypes); - if (!isa_and_nonnull<ConstantArrayType>( + assert(AggrDeductionCandidateParamTypes && + AggrDeductionCandidateParamTypesWithoutBraceElision); + if (!isa_and_present<ConstantArrayType>( SemaRef.Context.getAsArrayType(ElemType))) { ++Index; AggrDeductionCandidateParamTypes->push_back(ElemType); return; } + // For array types with known bounds, we still want the brace version even + // though the braces can be elided. + AggrDeductionCandidateParamTypesWithoutBraceElision->push_back(ElemType); } else { InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr, /*TopLevelOfInitList*/ true); @@ -10918,22 +10933,24 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( if (!(RD->getDefinition() && RD->isAggregate())) return; QualType Ty = Context.getRecordType(RD); - SmallVector<QualType, 8> ElementTypes; - - InitListChecker CheckInitList(*this, Entity, ListInit, Ty, ElementTypes); - if (!CheckInitList.HadError()) { + auto BuildAggregateDeductionGuide = [&](MutableArrayRef<QualType> + ElementTypes, + bool BracedVersion = false) { + if (ElementTypes.empty()) + return; // C++ [over.match.class.deduct]p1.8: // if e_i is of array type and x_i is a braced-init-list, T_i is an // rvalue reference to the declared type of e_i and // C++ [over.match.class.deduct]p1.9: - // if e_i is of array type and x_i is a bstring-literal, T_i is an + // if e_i is of array type and x_i is a string-literal, T_i is an // lvalue reference to the const-qualified declared type of e_i and // C++ [over.match.class.deduct]p1.10: // otherwise, T_i is the declared type of e_i - for (int I = 0, E = ListInit->getNumInits(); + for (int I = 0, E = BracedVersion ? ElementTypes.size() + : ListInit->getNumInits(); I < E && !isa<PackExpansionType>(ElementTypes[I]); ++I) if (ElementTypes[I]->isArrayType()) { - if (isa<InitListExpr>(ListInit->getInit(I))) + if (isa<InitListExpr, DesignatedInitExpr>(ListInit->getInit(I))) ElementTypes[I] = Context.getRValueReferenceType(ElementTypes[I]); else if (isa<StringLiteral>( ListInit->getInit(I)->IgnoreParenImpCasts())) @@ -10951,7 +10968,16 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( /*AllowAggregateDeductionCandidate=*/true); HasAnyDeductionGuide = true; } - } + }; + SmallVector<QualType, 8> ElementTypes, ElementTypesWithoutBraceElision; + + InitListChecker CheckInitList(*this, Entity, ListInit, Ty, ElementTypes, + ElementTypesWithoutBraceElision); + if (CheckInitList.HadError()) + return; + BuildAggregateDeductionGuide(ElementTypes); + BuildAggregateDeductionGuide(ElementTypesWithoutBraceElision, + /*BracedVersion=*/true); }; for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) { diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 758ca14e4b1c3..a72b2f0de1a58 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -335,3 +335,22 @@ namespace TTP { // CHECK-NEXT: `-TemplateArgument type 'T':'type-parameter-0-0'{{$}} // CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0{{$}} // CHECK-NEXT: `-TemplateTypeParm {{.+}} 'T'{{$}} + +namespace GH83368 { + +template <int N> struct A { + int f1[N]; +}; + +A a{.f1 = {1}}; + +} // namespace GH83368 + +namespace GH64625 { +template <class T> struct X { + T t[2]; +}; + +X x = {{1, 2}}; + +} // namespace GH64625 >From 6c723e85d59317cf415b8aa96fc7327772078391 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Mon, 10 Jun 2024 11:49:56 +0800 Subject: [PATCH 2/2] Release notes & AST verification. --- clang/docs/ReleaseNotes.rst | 1 + clang/test/SemaTemplate/deduction-guide.cpp | 69 ++++++++++++++++++--- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0c700d23257bf..e5efcae2289c6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -823,6 +823,7 @@ Bug Fixes to C++ Support differering by their constraints when only one of these function was variadic. - Fix a crash when a variable is captured by a block nested inside a lambda. (Fixes #GH93625). - Fixed a type constraint substitution issue involving a generic lambda expression. (#GH93821) +- Fixed two issues when building CTAD deduction guides for aggregates. (#GH64625), (#GH83368). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index a72b2f0de1a58..1cce455d966df 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -336,6 +336,50 @@ namespace TTP { // CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0{{$}} // CHECK-NEXT: `-TemplateTypeParm {{.+}} 'T'{{$}} +namespace GH64625 { + +template <class T> struct X { + T t[2]; +}; + +X x = {{1, 2}}, y = {1, 2}; + +// CHECK-LABEL: Dumping GH64625::<deduction guide for X>: +// CHECK-NEXT: FunctionTemplateDecl {{.+}} <{{.+}}:[[#@LINE - 7]]:1, col:27> col:27 implicit <deduction guide for X> +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} <col:11, col:17> col:17 referenced class depth 0 index 0 T +// CHECK: |-CXXDeductionGuideDecl {{.+}} <col:27> col:27 implicit <deduction guide for X> 'auto (T (&&)[2]) -> X<T>' aggregate +// CHECK-NEXT: | `-ParmVarDecl {{.+}} <col:27> col:27 'T (&&)[2]' +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <col:27> col:27 implicit used <deduction guide for X> 'auto (int (&&)[2]) -> GH64625::X<int>' implicit_instantiation aggregate +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: `-ParmVarDecl {{.+}} <col:27> col:27 'int (&&)[2]' +// CHECK-NEXT: FunctionProtoType {{.+}} 'auto (T (&&)[2]) -> X<T>' dependent trailing_return +// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'X<T>' dependent +// CHECK-NEXT: | `-CXXRecord {{.+}} 'X' +// CHECK-NEXT: `-RValueReferenceType {{.+}} 'T (&&)[2]' dependent +// CHECK-NEXT: `-ConstantArrayType {{.+}} 'T[2]' dependent 2 +// CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0 +// CHECK-NEXT: `-TemplateTypeParm {{.+}} 'T' + +// Brace-elision version: +// CHECK: |-CXXDeductionGuideDecl {{.+}} <col:27> col:27 implicit <deduction guide for X> 'auto (T, T) -> X<T>' aggregate +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:27> col:27 'T' +// CHECK-NEXT: | `-ParmVarDecl {{.+}} <col:27> col:27 'T' +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <col:27> col:27 implicit used <deduction guide for X> 'auto (int, int) -> GH64625::X<int>' implicit_instantiation aggregate +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:27> col:27 'int' +// CHECK-NEXT: `-ParmVarDecl {{.+}} <col:27> col:27 'int' +// CHECK-NEXT: FunctionProtoType {{.+}} 'auto (T, T) -> X<T>' dependent trailing_return +// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'X<T>' dependent +// CHECK-NEXT: | `-CXXRecord {{.+}} 'X' +// CHECK-NEXT: |-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0 +// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'T' +// CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0 +// CHECK-NEXT: `-TemplateTypeParm {{.+}} 'T' + +} // namespace GH64625 + namespace GH83368 { template <int N> struct A { @@ -344,13 +388,20 @@ template <int N> struct A { A a{.f1 = {1}}; -} // namespace GH83368 +// CHECK-LABEL: Dumping GH83368::<deduction guide for A>: +// CHECK-NEXT: FunctionTemplateDecl 0x{{.+}} <{{.+}}:[[#@LINE - 7]]:1, col:25> col:25 implicit <deduction guide for A> +// CHECK-NEXT: |-NonTypeTemplateParmDecl {{.+}} <col:11, col:15> col:15 referenced 'int' depth 0 index 0 N +// CHECK: |-CXXDeductionGuideDecl {{.+}} <col:25> col:25 implicit <deduction guide for A> 'auto (int (&&)[N]) -> A<N>' aggregate +// CHECK-NEXT: | `-ParmVarDecl {{.+}} <col:25> col:25 'int (&&)[N]' +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <col:25> col:25 implicit used <deduction guide for A> 'auto (int (&&)[1]) -> GH83368::A<1>' implicit_instantiation aggregate +// CHECK-NEXT: |-TemplateArgument integral '1' +// CHECK-NEXT: `-ParmVarDecl {{.+}} <col:25> col:25 'int (&&)[1]' +// CHECK-NEXT: FunctionProtoType {{.+}} 'auto (int (&&)[N]) -> A<N>' dependent trailing_return +// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'A<N>' dependent +// CHECK-NEXT: | `-CXXRecord {{.+}} 'A' +// CHECK-NEXT: `-RValueReferenceType {{.+}} 'int (&&)[N]' dependent +// CHECK-NEXT: `-DependentSizedArrayType {{.+}} 'int[N]' dependent +// CHECK-NEXT: |-BuiltinType {{.+}} 'int' +// CHECK-NEXT: `-DeclRefExpr {{.+}} <col:10> 'int' NonTypeTemplateParm {{.+}} 'N' 'int' -namespace GH64625 { -template <class T> struct X { - T t[2]; -}; - -X x = {{1, 2}}; - -} // namespace GH64625 +} // namespace GH83368 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits