[clang] [Clang] Fix two issues of CTAD for aggregates (PR #94889)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 8 20:54:59 PDT 2024


https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/94889

Fixes https://github.com/llvm/llvm-project/issues/64625
Fixes https://github.com/llvm/llvm-project/issues/83368

>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] [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



More information about the cfe-commits mailing list