[clang] [Clang] Fix two issues of CTAD for aggregates (PR #94889)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 9 20:50:43 PDT 2024
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 <zyn7109 at 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 <zyn7109 at 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
More information about the cfe-commits
mailing list