Author: Younan Zhang Date: 2024-06-13T17:47:03+08:00 New Revision: a144bf2b2511b47fc165755817eda17f79ef5476
URL: https://github.com/llvm/llvm-project/commit/a144bf2b2511b47fc165755817eda17f79ef5476 DIFF: https://github.com/llvm/llvm-project/commit/a144bf2b2511b47fc165755817eda17f79ef5476.diff LOG: [Clang] Fix handling of brace ellison when building deduction guides (#94889) Fixes two issues in two ways: 1) The `braced-init-list` consisted of `initializer-list` and `designated-initializer-list`, and thus the designated initializer is subject to [over.match.class.deduct]p1.8, which means the brace elision is also applicable on it for CTAD deduction guides. 2) When forming a deduction guide where the brace elision is applicable, we should also consider the presence of braces within the initializer. For example, given template <class T, class U> struct X { T t[2]; U u[3]; }; X x = {{1, 2}, 3, 4, 5}; we should establish such deduction guide AFAIU: `X(T (&&)[2], U, U, U) -> X<T, U>`. Fixes https://github.com/llvm/llvm-project/issues/64625 Fixes https://github.com/llvm/llvm-project/issues/83368 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaInit.cpp clang/test/SemaTemplate/deduction-guide.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 148ff05008552..8c2f737836a9d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -846,6 +846,7 @@ Bug Fixes to C++ Support - Fix a crash caused by improper use of ``__array_extent``. (#GH80474) - Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307), (#GH88081), (#GH89496), (#GH90669) and (#GH91633). +- Fixed handling of brace ellison when building deduction guides. (#GH64625), (#GH83368). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7244f3ef4e829..e805834c0fd38 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -513,7 +513,7 @@ class InitListChecker { : InitListChecker(S, Entity, IL, T, /*VerifyOnly=*/true, /*TreatUnavailableAsInvalid=*/false, /*InOverloadResolution=*/false, - &AggrDeductionCandidateParamTypes){}; + &AggrDeductionCandidateParamTypes) {} bool HadError() { return hadError; } @@ -1443,7 +1443,21 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // dependent non-array type or an array type with a value-dependent // bound assert(AggrDeductionCandidateParamTypes); - if (!isa_and_nonnull<ConstantArrayType>( + + // In the presence of a braced-init-list within the initializer, we should + // not perform brace-elision, even if brace elision would otherwise be + // applicable. For example, given: + // + // template <class T> struct Foo { + // T t[2]; + // }; + // + // Foo t = {{1, 2}}; + // + // we don't want the (T, T) but rather (T [2]) in terms of the initializer + // {{1, 2}}. + if (isa<InitListExpr, DesignatedInitExpr>(expr) || + !isa_and_present<ConstantArrayType>( SemaRef.Context.getAsArrayType(ElemType))) { ++Index; AggrDeductionCandidateParamTypes->push_back(ElemType); @@ -10940,14 +10954,14 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // 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(); 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())) diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp index 171c5413feaa7..163b36519950f 100644 --- a/clang/test/SemaTemplate/deduction-guide.cpp +++ b/clang/test/SemaTemplate/deduction-guide.cpp @@ -335,3 +335,142 @@ 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 GH64625 { + +template <class T> struct X { + T t[2]; +}; + +X x = {{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' + +template <class T, class U> struct TwoArrays { + T t[2]; + U u[3]; +}; + +TwoArrays ta = {{1, 2}, {3, 4, 5}}; +// CHECK-LABEL: Dumping GH64625::<deduction guide for TwoArrays>: +// CHECK-NEXT: FunctionTemplateDecl {{.+}} <{{.+}}:[[#@LINE - 7]]:1, col:36> col:36 implicit <deduction guide for TwoArrays> +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} <col:11, col:17> col:17 referenced class depth 0 index 0 T +// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} <col:20, col:26> col:26 referenced class depth 0 index 1 U +// CHECK: |-CXXDeductionGuideDecl {{.+}} <col:36> col:36 implicit <deduction guide for TwoArrays> 'auto (T (&&)[2], U (&&)[3]) -> TwoArrays<T, U>' aggregate +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:36> col:36 'T (&&)[2]' +// CHECK-NEXT: | `-ParmVarDecl {{.+}} <col:36> col:36 'U (&&)[3]' +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <col:36> col:36 implicit used <deduction guide for TwoArrays> 'auto (int (&&)[2], int (&&)[3]) -> GH64625::TwoArrays<int, int>' implicit_instantiation aggregate +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:36> col:36 'int (&&)[2]' +// CHECK-NEXT: `-ParmVarDecl {{.+}} <col:36> col:36 'int (&&)[3]' +// CHECK-NEXT: FunctionProtoType {{.+}} 'auto (T (&&)[2], U (&&)[3]) -> TwoArrays<T, U>' dependent trailing_return +// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'TwoArrays<T, U>' dependent +// CHECK-NEXT: | `-CXXRecord {{.+}} 'TwoArrays' +// 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' +// CHECK-NEXT: `-RValueReferenceType {{.+}} 'U (&&)[3]' dependent +// CHECK-NEXT: `-ConstantArrayType {{.+}} 'U[3]' dependent 3 +// CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1 +// CHECK-NEXT: `-TemplateTypeParm {{.+}} 'U' + +TwoArrays tb = {1, 2, {3, 4, 5}}; +// CHECK: |-CXXDeductionGuideDecl {{.+}} <col:36> col:36 implicit <deduction guide for TwoArrays> 'auto (T, T, U (&&)[3]) -> TwoArrays<T, U>' aggregate +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:36> col:36 'T' +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:36> col:36 'T' +// CHECK-NEXT: | `-ParmVarDecl {{.+}} <col:36> col:36 'U (&&)[3]' +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <col:36> col:36 implicit used <deduction guide for TwoArrays> 'auto (int, int, int (&&)[3]) -> GH64625::TwoArrays<int, int>' implicit_instantiation aggregate +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:36> col:36 'int' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:36> col:36 'int' +// CHECK-NEXT: `-ParmVarDecl {{.+}} <col:36> col:36 'int (&&)[3]' +// CHECK-NEXT: FunctionProtoType {{.+}} 'auto (T, T, U (&&)[3]) -> TwoArrays<T, U>' dependent trailing_return +// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'TwoArrays<T, U>' dependent +// CHECK-NEXT: | `-CXXRecord {{.+}} 'TwoArrays' +// 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' +// CHECK-NEXT: `-RValueReferenceType {{.+}} 'U (&&)[3]' dependent +// CHECK-NEXT: `-ConstantArrayType {{.+}} 'U[3]' dependent 3 +// CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1 +// CHECK-NEXT: `-TemplateTypeParm {{.+}} 'U' + +TwoArrays tc = {{1, 2}, 3, 4, 5}; +// CHECK: |-CXXDeductionGuideDecl {{.+}} <col:36> col:36 implicit <deduction guide for TwoArrays> 'auto (T (&&)[2], U, U, U) -> TwoArrays<T, U>' aggregate +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:36> col:36 'T (&&)[2]' +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:36> col:36 'U' +// CHECK-NEXT: | |-ParmVarDecl {{.+}} <col:36> col:36 'U' +// CHECK-NEXT: | `-ParmVarDecl {{.+}} <col:36> col:36 'U' +// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} <col:36> col:36 implicit used <deduction guide for TwoArrays> 'auto (int (&&)[2], int, int, int) -> GH64625::TwoArrays<int, int>' implicit_instantiation aggregate +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-TemplateArgument type 'int' +// CHECK-NEXT: | `-BuiltinType {{.+}} 'int' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:36> col:36 'int (&&)[2]' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:36> col:36 'int' +// CHECK-NEXT: |-ParmVarDecl {{.+}} <col:36> col:36 'int' +// CHECK-NEXT: `-ParmVarDecl {{.+}} <col:36> col:36 'int' +// CHECK-NEXT: FunctionProtoType {{.+}} 'auto (T (&&)[2], U, U, U) -> TwoArrays<T, U>' dependent trailing_return +// CHECK-NEXT: |-InjectedClassNameType {{.+}} 'TwoArrays<T, U>' dependent +// CHECK-NEXT: | `-CXXRecord {{.+}} 'TwoArrays' +// 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' +// CHECK-NEXT: |-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1 +// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U' +// CHECK-NEXT: |-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1 +// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U' +// CHECK-NEXT: `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1 +// CHECK-NEXT: `-TemplateTypeParm {{.+}} 'U' + +} // namespace GH64625 + +namespace GH83368 { + +template <int N> struct A { + int f1[N]; +}; + +A a{.f1 = {1}}; + +// 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 GH83368 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits